github.com/liloew/wireguard-go@v0.0.0-20220224014633-9cd745e6f114/main.go (about) 1 //go:build !windows 2 3 /* SPDX-License-Identifier: MIT 4 * 5 * Copyright (C) 2017-2021 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 "syscall" 17 18 "github.com/liloew/wireguard-go/conn" 19 "github.com/liloew/wireguard-go/device" 20 "github.com/liloew/wireguard-go/ipc" 21 "github.com/liloew/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) == 3 && 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 var nopi bool 71 if len(os.Args) < 2 || len(os.Args) > 3 { 72 printUsage() 73 return 74 } 75 76 switch os.Args[1] { 77 78 case "-f", "--foreground": 79 foreground = true 80 if len(os.Args) != 3 { 81 printUsage() 82 return 83 } 84 interfaceName = os.Args[2] 85 86 default: 87 foreground = false 88 if len(os.Args) != 2 { 89 printUsage() 90 return 91 } 92 interfaceName = os.Args[1] 93 } 94 95 if !foreground { 96 foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" 97 } 98 99 // get log level (default: info) 100 101 logLevel := func() int { 102 switch os.Getenv("LOG_LEVEL") { 103 case "verbose", "debug": 104 return device.LogLevelVerbose 105 case "error": 106 return device.LogLevelError 107 case "silent": 108 return device.LogLevelSilent 109 } 110 return device.LogLevelError 111 }() 112 113 // open TUN device (or use supplied fd) 114 115 tun, err := func() (tun.Device, error) { 116 tunFdStr := os.Getenv(ENV_WG_TUN_FD) 117 if tunFdStr == "" { 118 return tun.CreateTUN(interfaceName, device.DefaultMTU, nopi) 119 } 120 121 // construct tun device from supplied fd 122 123 fd, err := strconv.ParseUint(tunFdStr, 10, 32) 124 if err != nil { 125 return nil, err 126 } 127 128 err = syscall.SetNonblock(int(fd), true) 129 if err != nil { 130 return nil, err 131 } 132 133 file := os.NewFile(uintptr(fd), "") 134 return tun.CreateTUNFromFile(file, device.DefaultMTU, nopi) 135 }() 136 137 if err == nil { 138 realInterfaceName, err2 := tun.Name() 139 if err2 == nil { 140 interfaceName = realInterfaceName 141 } 142 } 143 144 logger := device.NewLogger( 145 logLevel, 146 fmt.Sprintf("(%s) ", interfaceName), 147 ) 148 149 logger.Verbosef("Starting wireguard-go version %s", Version) 150 151 if err != nil { 152 logger.Errorf("Failed to create TUN device: %v", err) 153 os.Exit(ExitSetupFailed) 154 } 155 156 // open UAPI file (or use supplied fd) 157 158 fileUAPI, err := func() (*os.File, error) { 159 uapiFdStr := os.Getenv(ENV_WG_UAPI_FD) 160 if uapiFdStr == "" { 161 return ipc.UAPIOpen(interfaceName) 162 } 163 164 // use supplied fd 165 166 fd, err := strconv.ParseUint(uapiFdStr, 10, 32) 167 if err != nil { 168 return nil, err 169 } 170 171 return os.NewFile(uintptr(fd), ""), nil 172 }() 173 if err != nil { 174 logger.Errorf("UAPI listen error: %v", err) 175 os.Exit(ExitSetupFailed) 176 return 177 } 178 // daemonize the process 179 180 if !foreground { 181 env := os.Environ() 182 env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD)) 183 env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD)) 184 env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND)) 185 files := [3]*os.File{} 186 if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent { 187 files[0], _ = os.Open(os.DevNull) 188 files[1] = os.Stdout 189 files[2] = os.Stderr 190 } else { 191 files[0], _ = os.Open(os.DevNull) 192 files[1], _ = os.Open(os.DevNull) 193 files[2], _ = os.Open(os.DevNull) 194 } 195 attr := &os.ProcAttr{ 196 Files: []*os.File{ 197 files[0], // stdin 198 files[1], // stdout 199 files[2], // stderr 200 tun.File(), 201 fileUAPI, 202 }, 203 Dir: ".", 204 Env: env, 205 } 206 207 path, err := os.Executable() 208 if err != nil { 209 logger.Errorf("Failed to determine executable: %v", err) 210 os.Exit(ExitSetupFailed) 211 } 212 213 process, err := os.StartProcess( 214 path, 215 os.Args, 216 attr, 217 ) 218 if err != nil { 219 logger.Errorf("Failed to daemonize: %v", err) 220 os.Exit(ExitSetupFailed) 221 } 222 process.Release() 223 return 224 } 225 226 device := device.NewDevice(tun, conn.NewDefaultBind(), logger) 227 228 logger.Verbosef("Device started") 229 230 errs := make(chan error) 231 term := make(chan os.Signal, 1) 232 233 uapi, err := ipc.UAPIListen(interfaceName, fileUAPI) 234 if err != nil { 235 logger.Errorf("Failed to listen on uapi socket: %v", err) 236 os.Exit(ExitSetupFailed) 237 } 238 239 go func() { 240 for { 241 conn, err := uapi.Accept() 242 if err != nil { 243 errs <- err 244 return 245 } 246 go device.IpcHandle(conn) 247 } 248 }() 249 250 logger.Verbosef("UAPI listener started") 251 252 // wait for program to terminate 253 254 signal.Notify(term, syscall.SIGTERM) 255 signal.Notify(term, os.Interrupt) 256 257 select { 258 case <-term: 259 case <-errs: 260 case <-device.Wait(): 261 } 262 263 // clean up 264 265 uapi.Close() 266 device.Close() 267 268 logger.Verbosef("Shutting down") 269 }