diff options
50 files changed, 491 insertions, 220 deletions
diff --git a/bind_test.go b/bind_test.go index 41c4225..47f5492 100644 --- a/bind_test.go +++ b/bind_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import "errors" @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/conn_default.go b/conn_default.go index 5b73c90..047d5f6 100644 --- a/conn_default.go +++ b/conn_default.go @@ -1,5 +1,10 @@ // +build !linux +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/conn_linux.go b/conn_linux.go index ff3c483..a428138 100644 --- a/conn_linux.go +++ b/conn_linux.go @@ -1,4 +1,6 @@ -/* Copyright 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. * * This implements userspace semantics of "sticky sockets", modeled after * WireGuard's kernelspace implementation. This is more or less a straight port diff --git a/constants.go b/constants.go index 8835f92..04b75d7 100644 --- a/constants.go +++ b/constants.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/cookie_test.go b/cookie_test.go index d745fe7..34c8ad4 100644 --- a/cookie_test.go +++ b/cookie_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/daemon_darwin.go b/daemon_darwin.go deleted file mode 100644 index 913af0e..0000000 --- a/daemon_darwin.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "errors" -) - -func Daemonize() error { - return errors.New("Not implemented on OSX") -} diff --git a/daemon_linux.go b/daemon_linux.go deleted file mode 100644 index e1aaede..0000000 --- a/daemon_linux.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "os" - "os/exec" -) - -/* Daemonizes the process on linux - * - * This is done by spawning and releasing a copy with the --foreground flag - */ -func Daemonize(attr *os.ProcAttr) error { - // I would like to use os.Executable, - // however this means dropping support for Go <1.8 - path, err := exec.LookPath(os.Args[0]) - if err != nil { - return err - } - - argv := []string{os.Args[0], "--foreground"} - argv = append(argv, os.Args[1:]...) - process, err := os.StartProcess( - path, - argv, - attr, - ) - if err != nil { - return err - } - process.Release() - return nil -} diff --git a/daemon_windows.go b/daemon_windows.go deleted file mode 100644 index 527718a..0000000 --- a/daemon_windows.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "os" -) - -/* Daemonizes the process on windows - * - * This is done by spawning and releasing a copy with the --foreground flag - */ - -func Daemonize() error { - argv := []string{os.Args[0], "--foreground"} - argv = append(argv, os.Args[1:]...) - attr := &os.ProcAttr{ - Dir: ".", - Env: os.Environ(), - Files: []*os.File{ - os.Stdin, - nil, - nil, - }, - } - process, err := os.StartProcess( - argv[0], - argv, - attr, - ) - if err != nil { - return err - } - process.Release() - return nil -} @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/device_test.go b/device_test.go index abd0208..7af52b2 100644 --- a/device_test.go +++ b/device_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main /* Create two device instances and simulate full WireGuard interaction diff --git a/endpoint_test.go b/endpoint_test.go index 7021e48..5dd6cb4 100644 --- a/endpoint_test.go +++ b/endpoint_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/helper_test.go b/helper_test.go index 41e6b72..a8adcd7 100644 --- a/helper_test.go +++ b/helper_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/kdf_test.go b/kdf_test.go index a89dacc..fa4a2d2 100644 --- a/kdf_test.go +++ b/kdf_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -14,8 +19,9 @@ const ( ) const ( - ENV_WG_TUN_FD = "WG_TUN_FD" - ENV_WG_UAPI_FD = "WG_UAPI_FD" + ENV_WG_TUN_FD = "WG_TUN_FD" + ENV_WG_UAPI_FD = "WG_UAPI_FD" + ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND" ) func printUsage() { @@ -23,7 +29,45 @@ func printUsage() { fmt.Printf("%s [-f/--foreground] INTERFACE-NAME\n", os.Args[0]) } +func warning() { + shouldQuit := false + + 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" { + shouldQuit = os.Getenv("WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD") != "1" + + 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") + 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") + } + } + fmt.Fprintln(os.Stderr, "W G") + fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING") + + if shouldQuit { + os.Exit(1) + } +} + func main() { + warning() // parse arguments @@ -53,6 +97,10 @@ func main() { interfaceName = os.Args[1] } + if !foreground { + foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" + } + // get log level (default: info) logLevel := func() int { @@ -67,13 +115,6 @@ func main() { return LogLevelInfo }() - logger := NewLogger( - logLevel, - fmt.Sprintf("(%s) ", interfaceName), - ) - - logger.Debug.Println("Debug log enabled") - // open TUN device (or use supplied fd) tun, err := func() (TUNDevice, error) { @@ -93,6 +134,21 @@ func main() { return CreateTUNFromFile(file) }() + 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") + + if err != nil { logger.Error.Println("Failed to create TUN device:", err) os.Exit(ExitSetupFailed) @@ -127,6 +183,7 @@ func main() { env := os.Environ() env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD)) env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD)) + env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND)) attr := &os.ProcAttr{ Files: []*os.File{ nil, // stdin @@ -138,18 +195,26 @@ func main() { Dir: ".", Env: env, } - err = Daemonize(attr) + + 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, + ) if err != nil { logger.Error.Println("Failed to daemonize:", err) os.Exit(ExitSetupFailed) } + process.Release() return } - // increase number of go workers (for Go <1.5) - - runtime.GOMAXPROCS(runtime.NumCPU()) - // create wireguard device device := NewDevice(tun, logger) @@ -162,6 +227,10 @@ func main() { term := make(chan os.Signal) uapi, err := UAPIListen(interfaceName, fileUAPI) + if err != nil { + logger.Error.Println("Failed to listen on uapi socket:", err) + os.Exit(ExitSetupFailed) + } go func() { for { @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/noise-helpers.go b/noise-helpers.go index 1e2de5f..6e23d83 100644 --- a/noise-helpers.go +++ b/noise-helpers.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/noise-protocol.go b/noise-protocol.go index 6440c97..b880ede 100644 --- a/noise-protocol.go +++ b/noise-protocol.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/noise-types.go b/noise-types.go index 1a944df..58aa0c2 100644 --- a/noise-types.go +++ b/noise-types.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/noise_test.go b/noise_test.go index 5e9d44b..958a4ef 100644 --- a/noise_test.go +++ b/noise_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/ratelimiter/ratelimiter.go b/ratelimiter/ratelimiter.go index 006900a..1aa6813 100644 --- a/ratelimiter/ratelimiter.go +++ b/ratelimiter/ratelimiter.go @@ -1,8 +1,9 @@ -package ratelimiter - -/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ -/* This file contains a port of the rate-limiter from the linux kernel version */ +package ratelimiter import ( "net" diff --git a/ratelimiter/ratelimiter_test.go b/ratelimiter/ratelimiter_test.go index 37339ee..9bdaa4d 100644 --- a/ratelimiter/ratelimiter_test.go +++ b/ratelimiter/ratelimiter_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package ratelimiter import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main /* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ diff --git a/replay_test.go b/replay_test.go index f697701..77180e5 100644 --- a/replay_test.go +++ b/replay_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main func signalSend(s chan<- struct{}) { diff --git a/tai64n/tai64n.go b/tai64n/tai64n.go index da5257c..1c7f42b 100644 --- a/tai64n/tai64n.go +++ b/tai64n/tai64n.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package tai64n import ( diff --git a/tai64n/tai64n_test.go b/tai64n/tai64n_test.go index 389b65c..62e7b1b 100644 --- a/tai64n/tai64n_test.go +++ b/tai64n/tai64n_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package tai64n import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/trie_rand_test.go b/trie_rand_test.go index 840d269..157c270 100644 --- a/trie_rand_test.go +++ b/trie_rand_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/trie_test.go b/trie_test.go index 9d53df3..3c3b5ba 100644 --- a/trie_test.go +++ b/trie_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/tun_darwin.go b/tun_darwin.go index 87f6af6..5514563 100644 --- a/tun_darwin.go +++ b/tun_darwin.go @@ -1,22 +1,17 @@ -/* Copyright (c) 2016, Song Gao <song@gao.io> - * All rights reserved. +/* SPDX-License-Identifier: GPL-2.0 * - * Code from https://github.com/songgao/water + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ package main import ( "encoding/binary" - "errors" "fmt" - "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" "golang.org/x/sys/unix" - "io" "net" "os" - "sync" "time" "unsafe" ) @@ -36,36 +31,32 @@ type sockaddrCtl struct { scReserved [5]uint32 } -// NativeTUN is a hack to work around the first 4 bytes "packet +// NativeTun is a hack to work around the first 4 bytes "packet // information" because there doesn't seem to be an IFF_NO_PI for darwin. -type NativeTUN struct { +type NativeTun struct { name string - f io.ReadWriteCloser + fd *os.File mtu int - rMu sync.Mutex - rBuf []byte - - wMu sync.Mutex - wBuf []byte - events chan TUNEvent errors chan error } var sockaddrCtlSize uintptr = 32 -func CreateTUN(name string) (ifce TUNDevice, err error) { +func CreateTUN(name string) (TUNDevice, error) { ifIndex := -1 - fmt.Sscanf(name, "utun%d", &ifIndex) - if ifIndex < 0 { - return nil, fmt.Errorf("error parsing interface name %s, must be utun[0-9]+", name) + if (name != "utun") { + fmt.Sscanf(name, "utun%d", &ifIndex) + if ifIndex < 0 { + return nil, fmt.Errorf("Interface name must be utun[0-9]*") + } } fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2) if err != nil { - return nil, fmt.Errorf("error in unix.Socket: %v", err) + return nil, err } var ctlInfo = &struct { @@ -83,8 +74,7 @@ func CreateTUN(name string) (ifce TUNDevice, err error) { ) if errno != 0 { - err = errno - return nil, fmt.Errorf("error in unix.Syscall(unix.SYS_IOTL, ...): %v", err) + return nil, fmt.Errorf("_CTLIOCGINFO: %v", errno) } sc := sockaddrCtl{ @@ -105,148 +95,139 @@ func CreateTUN(name string) (ifce TUNDevice, err error) { ) if errno != 0 { - err = errno - return nil, fmt.Errorf("error in unix.RawSyscall(unix.SYS_CONNECT, ...): %v", err) + return nil, fmt.Errorf("SYS_CONNECT: %v", errno) } - // read (new) name of interface + tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), "")) - var ifName struct { - name [16]byte + if err == nil && name == "utun" { + fmt.Printf("OS assigned interface: %s\n", tun.(*NativeTun).name) } - ifNameSize := uintptr(16) - _, _, errno = unix.Syscall6( - unix.SYS_GETSOCKOPT, - uintptr(fd), - 2, /* #define SYSPROTO_CONTROL 2 */ - 2, /* #define UTUN_OPT_IFNAME 2 */ - uintptr(unsafe.Pointer(&ifName)), - uintptr(unsafe.Pointer(&ifNameSize)), 0) + return tun, err +} - if errno != 0 { - err = errno - return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err) - } +func CreateTUNFromFile(file *os.File) (TUNDevice, error) { - device := &NativeTUN{ - name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), - f: os.NewFile(uintptr(fd), string(ifName.name[:])), + tun := &NativeTun{ + fd: file, mtu: 1500, events: make(chan TUNEvent, 10), errors: make(chan error, 1), } - // start listener + _, err := tun.Name() + if err != nil { + return nil, err + } - go func(native *NativeTUN) { - // TODO: Fix this very niave implementation + // TODO: Fix this very naive implementation + go func(tun *NativeTun) { var ( statusUp bool statusMTU int ) for ; ; time.Sleep(time.Second) { - intr, err := net.InterfaceByName(device.name) + intr, err := net.InterfaceByName(tun.name) if err != nil { - native.errors <- err + tun.errors <- err return } // Up / Down event up := (intr.Flags & net.FlagUp) != 0 if up != statusUp && up { - native.events <- TUNEventUp + tun.events <- TUNEventUp } if up != statusUp && !up { - native.events <- TUNEventDown + tun.events <- TUNEventDown } statusUp = up // MTU changes if intr.MTU != statusMTU { - native.events <- TUNEventMTUUpdate + tun.events <- TUNEventMTUUpdate } statusMTU = intr.MTU } - }(device) + }(tun) // set default MTU + err = tun.setMTU(DefaultMTU) - err = device.setMTU(DefaultMTU) - - return device, err + return tun, err } -var _ io.ReadWriteCloser = (*NativeTUN)(nil) +func (tun *NativeTun) Name() (string, error) { -func (t *NativeTUN) Events() chan TUNEvent { - return t.events -} + var ifName struct { + name [16]byte + } + ifNameSize := uintptr(16) -func (t *NativeTUN) Read(to []byte) (int, error) { - t.rMu.Lock() - defer t.rMu.Unlock() + _, _, errno := unix.Syscall6( + unix.SYS_GETSOCKOPT, + uintptr(tun.fd.Fd()), + 2, /* #define SYSPROTO_CONTROL 2 */ + 2, /* #define UTUN_OPT_IFNAME 2 */ + uintptr(unsafe.Pointer(&ifName)), + uintptr(unsafe.Pointer(&ifNameSize)), 0) - if cap(t.rBuf) < len(to)+4 { - t.rBuf = make([]byte, len(to)+4) + if errno != 0 { + return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno) } - t.rBuf = t.rBuf[:len(to)+4] - n, err := t.f.Read(t.rBuf) - copy(to, t.rBuf[4:]) - return n - 4, err + tun.name = string(ifName.name[:ifNameSize-1]) + return tun.name, nil } -func (t *NativeTUN) Write(from []byte) (int, error) { +func (tun *NativeTun) File() *os.File { + return tun.fd +} - if len(from) == 0 { - return 0, unix.EIO - } +func (tun *NativeTun) Events() chan TUNEvent { + return tun.events +} - t.wMu.Lock() - defer t.wMu.Unlock() +func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { - if cap(t.wBuf) < len(from)+4 { - t.wBuf = make([]byte, len(from)+4) + buff = buff[offset-4:] + n, err := tun.fd.Read(buff[:]) + if n < 4 { + return 0, err } - t.wBuf = t.wBuf[:len(from)+4] - - // determine the IP Family for the NULL L2 Header + return n - 4, err +} - ipVer := from[0] >> 4 - if ipVer == ipv4.Version { - t.wBuf[3] = unix.AF_INET - } else if ipVer == ipv6.Version { - t.wBuf[3] = unix.AF_INET6 - } else { - return 0, errors.New("Unable to determine IP version from packet.") - } +func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { - copy(t.wBuf[4:], from) + // reserve space for header - n, err := t.f.Write(t.wBuf) - return n - 4, err -} + buff = buff[offset-4:] -func (t *NativeTUN) Close() error { + // add packet information header - // lock to make sure no read/write is in process. + buff[0] = 0x00 + buff[1] = 0x00 + buff[2] = 0x00 - t.rMu.Lock() - defer t.rMu.Unlock() + if buff[4]>>4 == ipv6.Version { + buff[3] = unix.AF_INET6 + } else { + buff[3] = unix.AF_INET + } - t.wMu.Lock() - defer t.wMu.Unlock() + // write - return t.f.Close() + return tun.fd.Write(buff) } -func (t *NativeTUN) Name() string { - return t.name +func (tun *NativeTun) Close() error { + return tun.fd.Close() } -func (t *NativeTUN) setMTU(n int) error { +func (tun *NativeTun) setMTU(n int) error { // open datagram socket @@ -267,7 +248,7 @@ func (t *NativeTUN) setMTU(n int) error { // do ioctl call var ifr [32]byte - copy(ifr[:], t.name) + copy(ifr[:], tun.name) binary.LittleEndian.PutUint32(ifr[16:20], uint32(n)) _, _, errno := unix.Syscall( unix.SYS_IOCTL, @@ -277,13 +258,13 @@ func (t *NativeTUN) setMTU(n int) error { ) if errno != 0 { - return fmt.Errorf("Failed to set MTU on %s", t.name) + return fmt.Errorf("Failed to set MTU on %s", tun.name) } return nil } -func (t *NativeTUN) MTU() (int, error) { +func (tun *NativeTun) MTU() (int, error) { // open datagram socket @@ -302,7 +283,7 @@ func (t *NativeTUN) MTU() (int, error) { // do ioctl call var ifr [64]byte - copy(ifr[:], t.name) + copy(ifr[:], tun.name) _, _, errno := unix.Syscall( unix.SYS_IOCTL, uintptr(fd), @@ -310,7 +291,7 @@ func (t *NativeTUN) MTU() (int, error) { uintptr(unsafe.Pointer(&ifr[0])), ) if errno != 0 { - return 0, fmt.Errorf("Failed to get MTU on %s", t.name) + return 0, fmt.Errorf("Failed to get MTU on %s", tun.name) } // convert result to signed 32-bit int diff --git a/tun_linux.go b/tun_linux.go index b0ffa00..a74a9cc 100644 --- a/tun_linux.go +++ b/tun_linux.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + /* Copyright 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */ package main diff --git a/tun_windows.go b/tun_windows.go index 0711032..c0c9ff8 100644 --- a/tun_windows.go +++ b/tun_windows.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/uapi_darwin.go b/uapi_darwin.go index 2850184..69b0e3d 100644 --- a/uapi_darwin.go +++ b/uapi_darwin.go @@ -1,12 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( + "errors" "fmt" "golang.org/x/sys/unix" "net" "os" "path" - "time" ) const ( @@ -22,6 +27,8 @@ type UAPIListener struct { listener net.Listener // unix socket listener connNew chan net.Conn connErr chan error + kqueueFd int + keventFd int } func (l *UAPIListener) Accept() (net.Conn, error) { @@ -37,48 +44,74 @@ func (l *UAPIListener) Accept() (net.Conn, error) { } func (l *UAPIListener) Close() error { - return l.listener.Close() + err1 := unix.Close(l.kqueueFd) + err2 := unix.Close(l.keventFd) + err3 := l.listener.Close() + if err1 != nil { + return err1 + } + if err2 != nil { + return err2 + } + return err3 } func (l *UAPIListener) Addr() net.Addr { return nil } -func NewUAPIListener(name string) (net.Listener, error) { +func UAPIListen(name string, file *os.File) (net.Listener, error) { - // check if path exist + // wrap file in listener - err := os.MkdirAll(socketDirectory, 077) - if err != nil && !os.IsExist(err) { + listener, err := net.FileListener(file) + if err != nil { return nil, err } - // open UNIX socket + uapi := &UAPIListener{ + listener: listener, + connNew: make(chan net.Conn, 1), + connErr: make(chan error, 1), + } socketPath := path.Join( socketDirectory, fmt.Sprintf(socketName, name), ) - listener, err := net.Listen("unix", socketPath) + // watch for deletion of socket + + uapi.kqueueFd, err = unix.Kqueue() if err != nil { return nil, err } - - uapi := &UAPIListener{ - listener: listener, - connNew: make(chan net.Conn, 1), - connErr: make(chan error, 1), + uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0) + if err != nil { + unix.Close(uapi.kqueueFd) + return nil, err } - // watch for deletion of socket - go func(l *UAPIListener) { - for ; ; time.Sleep(time.Second) { - if _, err := os.Stat(socketPath); os.IsNotExist(err) { + event := unix.Kevent_t{ + Ident: uint64(uapi.keventFd), + Filter: unix.EVFILT_VNODE, + Flags: unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT, + Fflags: unix.NOTE_WRITE, + } + events := make([]unix.Kevent_t, 1) + n := 1 + var kerr error + for { + // start with lstat to avoid race condition + if _, err := os.Lstat(socketPath); os.IsNotExist(err) { l.connErr <- err return } + if kerr != nil || n != 1 { + return + } + n, kerr = unix.Kevent(uapi.kqueueFd, []unix.Kevent_t{event}, events, nil) } }(uapi) @@ -97,3 +130,56 @@ func NewUAPIListener(name string) (net.Listener, error) { return uapi, nil } + +func UAPIOpen(name string) (*os.File, error) { + + // check if path exist + + err := os.MkdirAll(socketDirectory, 0600) + if err != nil && !os.IsExist(err) { + return nil, err + } + + // open UNIX socket + + socketPath := path.Join( + socketDirectory, + fmt.Sprintf(socketName, name), + ) + + addr, err := net.ResolveUnixAddr("unix", socketPath) + if err != nil { + return nil, err + } + + listener, err := func() (*net.UnixListener, error) { + + // initial connection attempt + + listener, err := net.ListenUnix("unix", addr) + if err == nil { + return listener, nil + } + + // check if socket already active + + _, err = net.Dial("unix", socketPath) + if err == nil { + return nil, errors.New("unix socket in use") + } + + // cleanup & attempt again + + err = os.Remove(socketPath) + if err != nil { + return nil, err + } + return net.ListenUnix("unix", addr) + }() + + if err != nil { + return nil, err + } + + return listener.File() +} diff --git a/uapi_linux.go b/uapi_linux.go index f97a18a..c40472e 100644 --- a/uapi_linux.go +++ b/uapi_linux.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main import ( diff --git a/uapi_windows.go b/uapi_windows.go index 7807235..01f5505 100644 --- a/uapi_windows.go +++ b/uapi_windows.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package main /* UAPI on windows uses a bidirectional named pipe diff --git a/xchacha20poly1305/xchacha20.go b/xchacha20poly1305/xchacha20.go index a6e59f0..bd27f02 100644 --- a/xchacha20poly1305/xchacha20.go +++ b/xchacha20poly1305/xchacha20.go @@ -1,6 +1,8 @@ -// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. -// Use of this source code is governed by a license that can be -// found in the LICENSE file. +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2016 Andreas Auernhammer. All Rights Reserved. + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ package xchacha20poly1305 diff --git a/xchacha20poly1305/xchacha20_test.go b/xchacha20poly1305/xchacha20_test.go index 5d5b78f..c0d11d7 100644 --- a/xchacha20poly1305/xchacha20_test.go +++ b/xchacha20poly1305/xchacha20_test.go @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + package xchacha20poly1305 import ( |