2019-02-04 16:29:52 +00:00
// +build !windows
2019-01-02 00:55:51 +00:00
/ * SPDX - License - Identifier : MIT
2018-05-03 13:04:00 +00:00
*
2019-01-02 00:55:51 +00:00
* Copyright ( C ) 2017 - 2019 WireGuard LLC . All Rights Reserved .
2018-05-03 13:04:00 +00:00
* /
2017-05-30 20:36:49 +00:00
package main
2017-06-26 11:14:02 +00:00
import (
2017-07-20 13:06:24 +00:00
"fmt"
2017-06-29 12:39:21 +00:00
"os"
2017-08-01 10:14:38 +00:00
"os/signal"
2018-05-04 17:50:08 +00:00
"runtime"
2017-11-14 17:26:28 +00:00
"strconv"
2018-05-21 03:39:25 +00:00
"syscall"
2019-05-14 07:09:52 +00:00
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
2017-11-14 17:26:28 +00:00
)
2017-11-30 22:30:29 +00:00
const (
ExitSetupSuccess = 0
ExitSetupFailed = 1
)
2017-11-14 17:26:28 +00:00
const (
2018-05-04 17:50:08 +00:00
ENV_WG_TUN_FD = "WG_TUN_FD"
ENV_WG_UAPI_FD = "WG_UAPI_FD"
2018-05-03 12:50:57 +00:00
ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
2017-06-26 11:14:02 +00:00
)
2017-06-04 19:48:15 +00:00
2017-07-20 13:06:24 +00:00
func printUsage ( ) {
fmt . Printf ( "usage:\n" )
fmt . Printf ( "%s [-f/--foreground] INTERFACE-NAME\n" , os . Args [ 0 ] )
}
2018-05-04 17:50:08 +00:00
func warning ( ) {
2019-04-18 22:48:09 +00:00
if runtime . GOOS != "linux" || os . Getenv ( ENV_WG_PROCESS_FOREGROUND ) == "1" {
2018-05-14 13:58:40 +00:00
return
}
2019-04-18 22:48:09 +00:00
shouldQuit := os . Getenv ( "WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD" ) != "1"
2018-05-07 20:27:03 +00:00
2018-05-04 17:50:08 +00:00
fmt . Fprintln ( os . Stderr , "WARNING WARNING WARNING WARNING WARNING WARNING WARNING" )
fmt . Fprintln ( os . Stderr , "W G" )
2019-04-18 22:48:09 +00:00
fmt . Fprintln ( os . Stderr , "W You are running this software on a Linux kernel, G" )
fmt . Fprintln ( os . Stderr , "W which is probably unnecessary and foolish. This G" )
fmt . Fprintln ( os . Stderr , "W is because the Linux kernel has built-in first G" )
fmt . Fprintln ( os . Stderr , "W class support for WireGuard, and this support is G" )
fmt . Fprintln ( os . Stderr , "W much more refined than this slower userspace G" )
fmt . Fprintln ( os . Stderr , "W implementation. For more information on G" )
fmt . Fprintln ( os . Stderr , "W installing the kernel module, please visit: G" )
fmt . Fprintln ( os . Stderr , "W https://www.wireguard.com/install G" )
if shouldQuit {
2018-05-04 17:50:08 +00:00
fmt . Fprintln ( os . Stderr , "W G" )
2019-04-18 22:48:09 +00:00
fmt . Fprintln ( os . Stderr , "W If you still want to use this program, against G" )
fmt . Fprintln ( os . Stderr , "W the advice here, please first export this G" )
fmt . Fprintln ( os . Stderr , "W environment variable: G" )
fmt . Fprintln ( os . Stderr , "W WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1 G" )
2018-05-04 17:50:08 +00:00
}
fmt . Fprintln ( os . Stderr , "W G" )
fmt . Fprintln ( os . Stderr , "WARNING WARNING WARNING WARNING WARNING WARNING WARNING" )
2018-05-07 20:27:03 +00:00
if shouldQuit {
os . Exit ( 1 )
}
2018-05-04 17:50:08 +00:00
}
func main ( ) {
2018-05-23 23:52:22 +00:00
if len ( os . Args ) == 2 && os . Args [ 1 ] == "--version" {
2019-03-03 03:04:41 +00:00
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 )
2018-05-23 23:52:22 +00:00
return
}
2018-05-04 17:50:08 +00:00
warning ( )
2018-05-03 02:49:35 +00:00
2017-07-15 11:41:02 +00:00
// parse arguments
var foreground bool
var interfaceName string
if len ( os . Args ) < 2 || len ( os . Args ) > 3 {
2017-07-20 13:06:24 +00:00
printUsage ( )
2017-07-15 11:41:02 +00:00
return
}
switch os . Args [ 1 ] {
2017-07-17 14:16:18 +00:00
2017-07-15 11:41:02 +00:00
case "-f" , "--foreground" :
foreground = true
if len ( os . Args ) != 3 {
2017-07-20 13:06:24 +00:00
printUsage ( )
2017-07-15 11:41:02 +00:00
return
}
interfaceName = os . Args [ 2 ]
2017-07-17 14:16:18 +00:00
2017-07-15 11:41:02 +00:00
default :
foreground = false
if len ( os . Args ) != 2 {
2017-07-20 13:06:24 +00:00
printUsage ( )
2017-07-15 11:41:02 +00:00
return
}
interfaceName = os . Args [ 1 ]
}
2018-05-03 12:50:57 +00:00
if ! foreground {
foreground = os . Getenv ( ENV_WG_PROCESS_FOREGROUND ) == "1"
}
2017-08-11 14:18:20 +00:00
// get log level (default: info)
logLevel := func ( ) int {
switch os . Getenv ( "LOG_LEVEL" ) {
case "debug" :
2019-03-03 03:04:41 +00:00
return device . LogLevelDebug
2017-08-11 14:18:20 +00:00
case "info" :
2019-03-03 03:04:41 +00:00
return device . LogLevelInfo
2017-08-11 14:18:20 +00:00
case "error" :
2019-03-03 03:04:41 +00:00
return device . LogLevelError
2018-05-14 01:38:06 +00:00
case "silent" :
2019-03-03 03:04:41 +00:00
return device . LogLevelSilent
2017-08-11 14:18:20 +00:00
}
2019-03-03 03:04:41 +00:00
return device . LogLevelInfo
2017-08-11 14:18:20 +00:00
} ( )
2017-11-17 13:36:08 +00:00
// open TUN device (or use supplied fd)
2017-07-15 11:41:02 +00:00
2019-06-10 21:33:40 +00:00
tun , err := func ( ) ( tun . Device , error ) {
2017-11-17 13:36:08 +00:00
tunFdStr := os . Getenv ( ENV_WG_TUN_FD )
2017-11-14 17:26:28 +00:00
if tunFdStr == "" {
2019-03-03 03:04:41 +00:00
return tun . CreateTUN ( interfaceName , device . DefaultMTU )
2017-11-14 17:26:28 +00:00
}
2017-10-27 08:43:37 +00:00
2017-11-17 13:36:08 +00:00
// construct tun device from supplied fd
2017-11-14 17:26:28 +00:00
fd , err := strconv . ParseUint ( tunFdStr , 10 , 32 )
if err != nil {
return nil , err
}
tun: use netpoll instead of rwcancel
The new sysconn function of Go 1.12 makes this possible:
package main
import "log"
import "os"
import "unsafe"
import "time"
import "syscall"
import "sync"
import "golang.org/x/sys/unix"
func main() {
fd, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}
var ifr [unix.IFNAMSIZ + 64]byte
copy(ifr[:], []byte("cheese"))
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = unix.IFF_TUN
var errno syscall.Errno
s, _ := fd.SyscallConn()
s.Control(func(fd uintptr) {
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
})
if errno != 0 {
log.Fatal(errno)
}
b := [4]byte{}
wait := sync.WaitGroup{}
wait.Add(1)
go func() {
_, err := fd.Read(b[:])
log.Print("Read errored: ", err)
wait.Done()
}()
time.Sleep(time.Second)
log.Print("Closing")
err = fd.Close()
if err != nil {
log.Print("Close errored: " , err)
}
wait.Wait()
log.Print("Exiting")
}
2019-02-27 00:48:58 +00:00
err = syscall . SetNonblock ( int ( fd ) , true )
if err != nil {
return nil , err
}
2017-11-17 13:36:08 +00:00
file := os . NewFile ( uintptr ( fd ) , "" )
2019-03-03 03:04:41 +00:00
return tun . CreateTUNFromFile ( file , device . DefaultMTU )
2017-11-14 17:26:28 +00:00
} ( )
2018-05-04 19:11:38 +00:00
if err == nil {
realInterfaceName , err2 := tun . Name ( )
if err2 == nil {
interfaceName = realInterfaceName
}
}
2019-03-03 03:04:41 +00:00
logger := device . NewLogger (
2018-05-04 19:11:38 +00:00
logLevel ,
fmt . Sprintf ( "(%s) " , interfaceName ) ,
)
2019-03-03 03:04:41 +00:00
logger . Info . Println ( "Starting wireguard-go version" , device . WireGuardGoVersion )
2018-05-29 23:09:18 +00:00
2018-05-04 19:11:38 +00:00
logger . Debug . Println ( "Debug log enabled" )
2017-11-14 17:26:28 +00:00
if err != nil {
logger . Error . Println ( "Failed to create TUN device:" , err )
2017-11-17 13:36:08 +00:00
os . Exit ( ExitSetupFailed )
2017-11-14 17:26:28 +00:00
}
2017-11-17 13:36:08 +00:00
// open UAPI file (or use supplied fd)
fileUAPI , err := func ( ) ( * os . File , error ) {
uapiFdStr := os . Getenv ( ENV_WG_UAPI_FD )
if uapiFdStr == "" {
2019-03-03 03:04:41 +00:00
return ipc . UAPIOpen ( interfaceName )
2017-11-17 13:36:08 +00:00
}
// use supplied fd
fd , err := strconv . ParseUint ( uapiFdStr , 10 , 32 )
if err != nil {
return nil , err
}
return os . NewFile ( uintptr ( fd ) , "" ) , nil
} ( )
if err != nil {
logger . Error . Println ( "UAPI listen error:" , err )
os . Exit ( ExitSetupFailed )
return
}
2017-11-14 17:26:28 +00:00
// daemonize the process
if ! foreground {
env := os . Environ ( )
2017-11-17 13:36:08 +00:00
env = append ( env , fmt . Sprintf ( "%s=3" , ENV_WG_TUN_FD ) )
env = append ( env , fmt . Sprintf ( "%s=4" , ENV_WG_UAPI_FD ) )
2018-05-03 12:50:57 +00:00
env = append ( env , fmt . Sprintf ( "%s=1" , ENV_WG_PROCESS_FOREGROUND ) )
2018-05-14 01:38:06 +00:00
files := [ 3 ] * os . File { }
2019-03-03 03:04:41 +00:00
if os . Getenv ( "LOG_LEVEL" ) != "" && logLevel != device . LogLevelSilent {
2018-05-14 18:06:33 +00:00
files [ 0 ] , _ = os . Open ( os . DevNull )
2018-05-14 01:38:06 +00:00
files [ 1 ] = os . Stdout
files [ 2 ] = os . Stderr
2018-05-14 18:06:33 +00:00
} else {
files [ 0 ] , _ = os . Open ( os . DevNull )
files [ 1 ] , _ = os . Open ( os . DevNull )
files [ 2 ] , _ = os . Open ( os . DevNull )
2018-05-14 01:38:06 +00:00
}
2017-11-14 17:26:28 +00:00
attr := & os . ProcAttr {
Files : [ ] * os . File {
2018-05-14 01:38:06 +00:00
files [ 0 ] , // stdin
files [ 1 ] , // stdout
files [ 2 ] , // stderr
2017-11-14 17:26:28 +00:00
tun . File ( ) ,
2017-11-17 13:36:08 +00:00
fileUAPI ,
2017-11-14 17:26:28 +00:00
} ,
Dir : "." ,
Env : env ,
}
2018-05-03 12:50:57 +00:00
path , err := os . Executable ( )
if err != nil {
logger . Error . Println ( "Failed to determine executable:" , err )
os . Exit ( ExitSetupFailed )
}
process , err := os . StartProcess (
path ,
os . Args ,
attr ,
)
2017-11-14 17:26:28 +00:00
if err != nil {
logger . Error . Println ( "Failed to daemonize:" , err )
2017-11-17 13:36:08 +00:00
os . Exit ( ExitSetupFailed )
2017-11-14 17:26:28 +00:00
}
2018-05-03 12:50:57 +00:00
process . Release ( )
2017-11-14 17:26:28 +00:00
return
}
2019-03-03 03:04:41 +00:00
device := device . NewDevice ( tun , logger )
2017-11-17 13:36:08 +00:00
2017-11-14 17:26:28 +00:00
logger . Info . Println ( "Device started" )
2017-06-04 19:48:15 +00:00
2017-08-01 10:14:38 +00:00
errs := make ( chan error )
2018-05-21 03:39:25 +00:00
term := make ( chan os . Signal , 1 )
2017-07-13 12:32:40 +00:00
2019-03-03 03:04:41 +00:00
uapi , err := ipc . UAPIListen ( interfaceName , fileUAPI )
2018-05-04 19:51:55 +00:00
if err != nil {
logger . Error . Println ( "Failed to listen on uapi socket:" , err )
os . Exit ( ExitSetupFailed )
}
2017-11-17 13:36:08 +00:00
2017-07-17 14:16:18 +00:00
go func ( ) {
for {
conn , err := uapi . Accept ( )
if err != nil {
2017-08-01 10:14:38 +00:00
errs <- err
return
2017-07-17 14:16:18 +00:00
}
2019-03-03 03:04:41 +00:00
go device . IpcHandle ( conn )
2017-07-13 12:32:40 +00:00
}
2017-07-17 14:16:18 +00:00
} ( )
2017-11-14 17:26:28 +00:00
logger . Info . Println ( "UAPI listener started" )
2017-08-01 10:14:38 +00:00
// wait for program to terminate
2018-05-21 03:39:25 +00:00
signal . Notify ( term , syscall . SIGTERM )
2017-08-01 10:14:38 +00:00
signal . Notify ( term , os . Interrupt )
select {
case <- term :
case <- errs :
2017-12-01 22:37:26 +00:00
case <- device . Wait ( ) :
2017-08-01 10:14:38 +00:00
}
2017-11-17 13:36:08 +00:00
// clean up
2017-08-01 10:14:38 +00:00
uapi . Close ( )
2017-11-17 13:36:08 +00:00
device . Close ( )
2017-08-01 10:14:38 +00:00
2017-11-14 17:26:28 +00:00
logger . Info . Println ( "Shutting down" )
2017-05-30 20:36:49 +00:00
}