github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/main.go (about) 1 // +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/tailscale/wireguard-go/conn" 19 "github.com/tailscale/wireguard-go/device" 20 "github.com/tailscale/wireguard-go/ipc" 21 "github.com/tailscale/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 tun, 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 = syscall.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 := tun.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 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 }