2018-05-03 13:04:00 +00:00
/ * SPDX - License - Identifier : GPL - 2.0
*
* Copyright ( C ) 2017 - 2018 Jason A . Donenfeld < Jason @ zx2c4 . com > . All Rights Reserved .
2018-05-18 22:34:56 +00:00
* Copyright ( C ) 2017 - 2018 Mathias N . Hall - Andersen < mathias @ hall - andersen . dk > .
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 (
2018-05-23 01:17:51 +00:00
"git.zx2c4.com/wireguard-go/tun"
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"
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 ( ) {
2018-05-14 13:58:40 +00:00
if os . Getenv ( ENV_WG_PROCESS_FOREGROUND ) == "1" {
return
}
2018-05-07 20:27:03 +00:00
shouldQuit := false
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" )
fmt . Fprintln ( os . Stderr , "W This is alpha software. It will very likely not G" )
fmt . Fprintln ( os . Stderr , "W do what it is supposed to do, and things may go G" )
fmt . Fprintln ( os . Stderr , "W horribly wrong. You have been warned. Proceed G" )
fmt . Fprintln ( os . Stderr , "W at your own risk. G" )
if runtime . GOOS == "linux" {
2018-05-07 20:27:03 +00:00
shouldQuit = os . Getenv ( "WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD" ) != "1"
2018-05-04 17:50:08 +00:00
fmt . Fprintln ( os . Stderr , "W G" )
fmt . Fprintln ( os . Stderr , "W Furthermore, you are running this software on a G" )
fmt . Fprintln ( os . Stderr , "W Linux kernel, which is probably unnecessary and G" )
fmt . Fprintln ( os . Stderr , "W foolish. This is because the Linux kernel has G" )
fmt . Fprintln ( os . Stderr , "W built-in first class support for WireGuard, and G" )
fmt . Fprintln ( os . Stderr , "W this support is much more refined than this G" )
fmt . Fprintln ( os . Stderr , "W program. For more information on installing the G" )
fmt . Fprintln ( os . Stderr , "W kernel module, please visit: G" )
fmt . Fprintln ( os . Stderr , "W https://www.wireguard.com/install G" )
2018-05-07 20:27:03 +00:00
if shouldQuit {
fmt . Fprintln ( os . Stderr , "W G" )
fmt . Fprintln ( os . Stderr , "W If you still want to use this program, against G" )
fmt . Fprintln ( os . Stderr , "W the sage 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" {
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" , WireGuardGoVersion , runtime . GOOS , runtime . GOARCH )
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" :
return LogLevelDebug
case "info" :
return LogLevelInfo
case "error" :
return LogLevelError
2018-05-14 01:38:06 +00:00
case "silent" :
return LogLevelSilent
2017-08-11 14:18:20 +00:00
}
return LogLevelInfo
} ( )
2017-11-17 13:36:08 +00:00
// open TUN device (or use supplied fd)
2017-07-15 11:41:02 +00:00
2018-05-23 00:10:54 +00:00
tun , err := func ( ) ( tun . TUNDevice , 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 == "" {
2018-05-23 00:10:54 +00:00
return tun . CreateTUN ( interfaceName , 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
}
2017-11-17 13:36:08 +00:00
file := os . NewFile ( uintptr ( fd ) , "" )
2018-05-23 00:10:54 +00:00
return tun . CreateTUNFromFile ( file , 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
}
}
logger := NewLogger (
logLevel ,
fmt . Sprintf ( "(%s) " , interfaceName ) ,
)
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 == "" {
return UAPIOpen ( interfaceName )
}
// 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 { }
2018-05-14 10:27:29 +00:00
if os . Getenv ( "LOG_LEVEL" ) != "" && logLevel != 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
}
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
2017-11-17 13:36:08 +00:00
uapi , err := 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
}
go ipcHandle ( device , 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
}