github.com/koomox/wireguard-go@v0.0.0-20230722134753-17a50b2f22a3/main.go (about) 1 //go:build !windows 2 3 /* SPDX-License-Identifier: MIT 4 * 5 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 6 */ 7 8 package main 9 10 import ( 11 "fmt" 12 "os" 13 "os/signal" 14 "runtime" 15 "strconv" 16 17 "golang.org/x/sys/unix" 18 "github.com/koomox/wireguard-go/conn" 19 "github.com/koomox/wireguard-go/device" 20 "github.com/koomox/wireguard-go/ipc" 21 "github.com/koomox/wireguard-go/tun" 22 ) 23 24 const ( 25 ExitSetupSuccess = 0 26 ExitSetupFailed = 1 27 ) 28 29 const ( 30 ENV_WG_TUN_FD = "WG_TUN_FD" 31 ENV_WG_UAPI_FD = "WG_UAPI_FD" 32 ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND" 33 ) 34 35 func printUsage() { 36 fmt.Printf("Usage: %s [-f/--foreground] INTERFACE-NAME\n", os.Args[0]) 37 } 38 39 func warning() { 40 switch runtime.GOOS { 41 case "linux", "freebsd", "openbsd": 42 if os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" { 43 return 44 } 45 default: 46 return 47 } 48 49 fmt.Fprintln(os.Stderr, "┌──────────────────────────────────────────────────────┐") 50 fmt.Fprintln(os.Stderr, "│ │") 51 fmt.Fprintln(os.Stderr, "│ Running wireguard-go is not required because this │") 52 fmt.Fprintln(os.Stderr, "│ kernel has first class support for WireGuard. For │") 53 fmt.Fprintln(os.Stderr, "│ information on installing the kernel module, │") 54 fmt.Fprintln(os.Stderr, "│ please visit: │") 55 fmt.Fprintln(os.Stderr, "│ https://www.wireguard.com/install/ │") 56 fmt.Fprintln(os.Stderr, "│ │") 57 fmt.Fprintln(os.Stderr, "└──────────────────────────────────────────────────────┘") 58 } 59 60 func main() { 61 if len(os.Args) == 2 && os.Args[1] == "--version" { 62 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", Version, runtime.GOOS, runtime.GOARCH) 63 return 64 } 65 66 warning() 67 68 var foreground bool 69 var interfaceName string 70 if len(os.Args) < 2 || len(os.Args) > 3 { 71 printUsage() 72 return 73 } 74 75 switch os.Args[1] { 76 77 case "-f", "--foreground": 78 foreground = true 79 if len(os.Args) != 3 { 80 printUsage() 81 return 82 } 83 interfaceName = os.Args[2] 84 85 default: 86 foreground = false 87 if len(os.Args) != 2 { 88 printUsage() 89 return 90 } 91 interfaceName = os.Args[1] 92 } 93 94 if !foreground { 95 foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" 96 } 97 98 // get log level (default: info) 99 100 logLevel := func() int { 101 switch os.Getenv("LOG_LEVEL") { 102 case "verbose", "debug": 103 return device.LogLevelVerbose 104 case "error": 105 return device.LogLevelError 106 case "silent": 107 return device.LogLevelSilent 108 } 109 return device.LogLevelError 110 }() 111 112 // open TUN device (or use supplied fd) 113 114 tdev, err := func() (tun.Device, error) { 115 tunFdStr := os.Getenv(ENV_WG_TUN_FD) 116 if tunFdStr == "" { 117 return tun.CreateTUN(interfaceName, device.DefaultMTU) 118 } 119 120 // construct tun device from supplied fd 121 122 fd, err := strconv.ParseUint(tunFdStr, 10, 32) 123 if err != nil { 124 return nil, err 125 } 126 127 err = unix.SetNonblock(int(fd), true) 128 if err != nil { 129 return nil, err 130 } 131 132 file := os.NewFile(uintptr(fd), "") 133 return tun.CreateTUNFromFile(file, device.DefaultMTU) 134 }() 135 136 if err == nil { 137 realInterfaceName, err2 := tdev.Name() 138 if err2 == nil { 139 interfaceName = realInterfaceName 140 } 141 } 142 143 logger := device.NewLogger( 144 logLevel, 145 fmt.Sprintf("(%s) ", interfaceName), 146 ) 147 148 logger.Verbosef("Starting wireguard-go version %s", Version) 149 150 if err != nil { 151 logger.Errorf("Failed to create TUN device: %v", err) 152 os.Exit(ExitSetupFailed) 153 } 154 155 // open UAPI file (or use supplied fd) 156 157 fileUAPI, err := func() (*os.File, error) { 158 uapiFdStr := os.Getenv(ENV_WG_UAPI_FD) 159 if uapiFdStr == "" { 160 return ipc.UAPIOpen(interfaceName) 161 } 162 163 // use supplied fd 164 165 fd, err := strconv.ParseUint(uapiFdStr, 10, 32) 166 if err != nil { 167 return nil, err 168 } 169 170 return os.NewFile(uintptr(fd), ""), nil 171 }() 172 if err != nil { 173 logger.Errorf("UAPI listen error: %v", err) 174 os.Exit(ExitSetupFailed) 175 return 176 } 177 // daemonize the process 178 179 if !foreground { 180 env := os.Environ() 181 env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD)) 182 env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD)) 183 env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND)) 184 files := [3]*os.File{} 185 if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent { 186 files[0], _ = os.Open(os.DevNull) 187 files[1] = os.Stdout 188 files[2] = os.Stderr 189 } else { 190 files[0], _ = os.Open(os.DevNull) 191 files[1], _ = os.Open(os.DevNull) 192 files[2], _ = os.Open(os.DevNull) 193 } 194 attr := &os.ProcAttr{ 195 Files: []*os.File{ 196 files[0], // stdin 197 files[1], // stdout 198 files[2], // stderr 199 tdev.File(), 200 fileUAPI, 201 }, 202 Dir: ".", 203 Env: env, 204 } 205 206 path, err := os.Executable() 207 if err != nil { 208 logger.Errorf("Failed to determine executable: %v", err) 209 os.Exit(ExitSetupFailed) 210 } 211 212 process, err := os.StartProcess( 213 path, 214 os.Args, 215 attr, 216 ) 217 if err != nil { 218 logger.Errorf("Failed to daemonize: %v", err) 219 os.Exit(ExitSetupFailed) 220 } 221 process.Release() 222 return 223 } 224 225 device := device.NewDevice(tdev, conn.NewDefaultBind(), logger) 226 227 logger.Verbosef("Device started") 228 229 errs := make(chan error) 230 term := make(chan os.Signal, 1) 231 232 uapi, err := ipc.UAPIListen(interfaceName, fileUAPI) 233 if err != nil { 234 logger.Errorf("Failed to listen on uapi socket: %v", err) 235 os.Exit(ExitSetupFailed) 236 } 237 238 go func() { 239 for { 240 conn, err := uapi.Accept() 241 if err != nil { 242 errs <- err 243 return 244 } 245 go device.IpcHandle(conn) 246 } 247 }() 248 249 logger.Verbosef("UAPI listener started") 250 251 // wait for program to terminate 252 253 signal.Notify(term, unix.SIGTERM) 254 signal.Notify(term, os.Interrupt) 255 256 select { 257 case <-term: 258 case <-errs: 259 case <-device.Wait(): 260 } 261 262 // clean up 263 264 uapi.Close() 265 device.Close() 266 267 logger.Verbosef("Shutting down") 268 }