From 258a9223b9ab18a973c44b238e029a0dc5640102 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 3 May 2018 04:49:35 +0200
Subject: [PATCH 1/7] Start to dust off Darwin

---
 daemon_linux.go => daemon.go |   9 +-
 daemon_darwin.go             |   9 --
 daemon_windows.go            |  34 ------
 main.go                      |   2 +
 tun_darwin.go                | 194 +++++++++++++++--------------------
 uapi_darwin.go               |  79 +++++++++++---
 warning_default.go           |  19 ++++
 warning_linux.go             |  39 +++++++
 8 files changed, 206 insertions(+), 179 deletions(-)
 rename daemon_linux.go => daemon.go (55%)
 delete mode 100644 daemon_darwin.go
 delete mode 100644 daemon_windows.go
 create mode 100644 warning_default.go
 create mode 100644 warning_linux.go

diff --git a/daemon_linux.go b/daemon.go
similarity index 55%
rename from daemon_linux.go
rename to daemon.go
index e1aaede..e2ded87 100644
--- a/daemon_linux.go
+++ b/daemon.go
@@ -2,17 +2,10 @@ 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])
+	path, err := os.Executable()
 	if err != nil {
 		return err
 	}
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_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
-}
diff --git a/main.go b/main.go
index 7742eef..3358469 100644
--- a/main.go
+++ b/main.go
@@ -25,6 +25,8 @@ func printUsage() {
 
 func main() {
 
+	Warning()
+
 	// parse arguments
 
 	var foreground bool
diff --git a/tun_darwin.go b/tun_darwin.go
index 87f6af6..d03ff48 100644
--- a/tun_darwin.go
+++ b/tun_darwin.go
@@ -1,22 +1,12 @@
-/* Copyright (c) 2016, Song Gao <song@gao.io>
- * All rights reserved.
- *
- * Code from https://github.com/songgao/water
- */
-
 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,26 +26,20 @@ 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 {
@@ -65,7 +49,7 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
 	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 +67,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 +88,133 @@ 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
+	return CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
+}
 
-	var ifName struct {
-		name [16]byte
-	}
-	ifNameSize := uintptr(16)
+func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
 
-	_, _, 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)
-
-	if errno != 0 {
-		err = errno
-		return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err)
-	}
-
-	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
-}
-
-func (t *NativeTUN) Read(to []byte) (int, error) {
-	t.rMu.Lock()
-	defer t.rMu.Unlock()
-
-	if cap(t.rBuf) < len(to)+4 {
-		t.rBuf = make([]byte, len(to)+4)
+	var ifName struct {
+		name [16]byte
 	}
-	t.rBuf = t.rBuf[:len(to)+4]
+	ifNameSize := uintptr(16)
 
-	n, err := t.f.Read(t.rBuf)
-	copy(to, t.rBuf[4:])
+	_, _, 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 errno != 0 {
+		return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno)
+	}
+
+	tun.name = string(ifName.name[:ifNameSize-1])
+	return tun.name, nil
+}
+
+func (tun *NativeTun) File() *os.File {
+	return tun.fd
+}
+
+func (tun *NativeTun) Events() chan TUNEvent {
+	return tun.events
+}
+
+func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
+
+	buff = buff[offset-4:]
+	n, err := tun.fd.Read(buff[:])
+	if n < 4 {
+		return 0, err
+	}
 	return n - 4, err
 }
 
-func (t *NativeTUN) Write(from []byte) (int, error) {
+func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
 
-	if len(from) == 0 {
-		return 0, unix.EIO
-	}
+	// reserve space for header
 
-	t.wMu.Lock()
-	defer t.wMu.Unlock()
+	buff = buff[offset-4:]
 
-	if cap(t.wBuf) < len(from)+4 {
-		t.wBuf = make([]byte, len(from)+4)
-	}
-	t.wBuf = t.wBuf[:len(from)+4]
+	// add packet information header
 
-	// determine the IP Family for the NULL L2 Header
+	buff[0] = 0x00
+	buff[1] = 0x00
+	buff[2] = 0x00
 
-	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
+	if buff[4]>>4 == ipv6.Version {
+		buff[3] = unix.AF_INET6
 	} else {
-		return 0, errors.New("Unable to determine IP version from packet.")
+		buff[3] = unix.AF_INET
 	}
 
-	copy(t.wBuf[4:], from)
+	// write
 
-	n, err := t.f.Write(t.wBuf)
-	return n - 4, err
+	return tun.fd.Write(buff)
 }
 
-func (t *NativeTUN) Close() error {
-
-	// lock to make sure no read/write is in process.
-
-	t.rMu.Lock()
-	defer t.rMu.Unlock()
-
-	t.wMu.Lock()
-	defer t.wMu.Unlock()
-
-	return t.f.Close()
+func (tun *NativeTun) Close() error {
+	return tun.fd.Close()
 }
 
-func (t *NativeTUN) Name() string {
-	return t.name
-}
-
-func (t *NativeTUN) setMTU(n int) error {
+func (tun *NativeTun) setMTU(n int) error {
 
 	// open datagram socket
 
@@ -267,7 +235,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 +245,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 +270,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 +278,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/uapi_darwin.go b/uapi_darwin.go
index 2850184..4cb4e62 100644
--- a/uapi_darwin.go
+++ b/uapi_darwin.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"errors"
 	"fmt"
 	"golang.org/x/sys/unix"
 	"net"
@@ -44,23 +45,11 @@ 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) {
-		return nil, err
-	}
-
-	// open UNIX socket
-
-	socketPath := path.Join(
-		socketDirectory,
-		fmt.Sprintf(socketName, name),
-	)
-
-	listener, err := net.Listen("unix", socketPath)
+	listener, err := net.FileListener(file)
 	if err != nil {
 		return nil, err
 	}
@@ -73,6 +62,13 @@ func NewUAPIListener(name string) (net.Listener, error) {
 
 	// watch for deletion of socket
 
+	socketPath := path.Join(
+		socketDirectory,
+		fmt.Sprintf(socketName, name),
+	)
+
+	// watch for deletion of socket
+
 	go func(l *UAPIListener) {
 		for ; ; time.Sleep(time.Second) {
 			if _, err := os.Stat(socketPath); os.IsNotExist(err) {
@@ -97,3 +93,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/warning_default.go b/warning_default.go
new file mode 100644
index 0000000..92d1b1d
--- /dev/null
+++ b/warning_default.go
@@ -0,0 +1,19 @@
+// +build !linux
+
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func Warning() {
+	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")
+	fmt.Fprintln(os.Stderr, "W                                                     G")
+	fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
+}
diff --git a/warning_linux.go b/warning_linux.go
new file mode 100644
index 0000000..d82805f
--- /dev/null
+++ b/warning_linux.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func Warning() {
+	shouldQuit := os.Getenv("WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD") != "1"
+
+	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")
+	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)
+	}
+}

From 209dd22ea0c6ea06aca47cb53f68ae2cf0d40831 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 3 May 2018 14:50:57 +0200
Subject: [PATCH 2/7] Daemonize with environment variable

---
 daemon.go | 25 -------------------------
 main.go   | 25 +++++++++++++++++++------
 2 files changed, 19 insertions(+), 31 deletions(-)
 delete mode 100644 daemon.go

diff --git a/daemon.go b/daemon.go
deleted file mode 100644
index e2ded87..0000000
--- a/daemon.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package main
-
-import (
-	"os"
-)
-
-func Daemonize(attr *os.ProcAttr) error {
-	path, err := os.Executable()
-	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/main.go b/main.go
index 3358469..f0705c8 100644
--- a/main.go
+++ b/main.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
-	"runtime"
 	"strconv"
 )
 
@@ -16,6 +15,7 @@ const (
 const (
 	ENV_WG_TUN_FD  = "WG_TUN_FD"
 	ENV_WG_UAPI_FD = "WG_UAPI_FD"
+	ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
 )
 
 func printUsage() {
@@ -55,6 +55,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 {
@@ -129,6 +133,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
@@ -140,18 +145,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)

From a040786645ec980059937fd6a1a361b160c1a809 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Thu, 3 May 2018 15:04:00 +0200
Subject: [PATCH 3/7] global: Add SPDX tags and copyright header

Mathias should probably add his copyright headers to each file too.
---
 bind_test.go                        | 5 +++++
 conn.go                             | 5 +++++
 conn_default.go                     | 5 +++++
 conn_linux.go                       | 4 +++-
 constants.go                        | 5 +++++
 cookie.go                           | 5 +++++
 cookie_test.go                      | 5 +++++
 device.go                           | 5 +++++
 device_test.go                      | 5 +++++
 endpoint_test.go                    | 5 +++++
 helper_test.go                      | 5 +++++
 index.go                            | 5 +++++
 ip.go                               | 5 +++++
 kdf_test.go                         | 5 +++++
 keypair.go                          | 5 +++++
 logger.go                           | 5 +++++
 main.go                             | 5 +++++
 misc.go                             | 5 +++++
 noise-helpers.go                    | 5 +++++
 noise-protocol.go                   | 5 +++++
 noise-types.go                      | 5 +++++
 noise_test.go                       | 5 +++++
 peer.go                             | 5 +++++
 ratelimiter/ratelimiter.go          | 9 +++++----
 ratelimiter/ratelimiter_test.go     | 5 +++++
 receive.go                          | 5 +++++
 replay.go                           | 5 +++++
 replay_test.go                      | 5 +++++
 routing.go                          | 5 +++++
 send.go                             | 5 +++++
 signal.go                           | 5 +++++
 tai64n/tai64n.go                    | 5 +++++
 tai64n/tai64n_test.go               | 5 +++++
 timer.go                            | 5 +++++
 timers.go                           | 5 +++++
 trie.go                             | 5 +++++
 trie_rand_test.go                   | 5 +++++
 trie_test.go                        | 5 +++++
 tun.go                              | 5 +++++
 tun_darwin.go                       | 5 +++++
 tun_linux.go                        | 5 +++++
 tun_windows.go                      | 5 +++++
 uapi.go                             | 5 +++++
 uapi_darwin.go                      | 5 +++++
 uapi_linux.go                       | 5 +++++
 uapi_windows.go                     | 5 +++++
 warning_default.go                  | 5 +++++
 warning_linux.go                    | 5 +++++
 xchacha20poly1305/xchacha20.go      | 8 +++++---
 xchacha20poly1305/xchacha20_test.go | 5 +++++
 50 files changed, 248 insertions(+), 8 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"
diff --git a/conn.go b/conn.go
index 6bb262c..082bbca 100644
--- a/conn.go
+++ b/conn.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/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 (
diff --git a/cookie.go b/cookie.go
index 813ddab..cfee367 100644
--- a/cookie.go
+++ b/cookie.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/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/device.go b/device.go
index dddb547..8b0d2a5 100644
--- a/device.go
+++ b/device.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/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 (
diff --git a/index.go b/index.go
index 1ba040e..c309f23 100644
--- a/index.go
+++ b/index.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/ip.go b/ip.go
index 752a404..7be9337 100644
--- a/ip.go
+++ b/ip.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/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 (
diff --git a/keypair.go b/keypair.go
index 1ab0649..eaf30b2 100644
--- a/keypair.go
+++ b/keypair.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/logger.go b/logger.go
index 0872ef9..784235c 100644
--- a/logger.go
+++ b/logger.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/main.go b/main.go
index f0705c8..4b8299a 100644
--- a/main.go
+++ b/main.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/misc.go b/misc.go
index 80e33f6..f94a617 100644
--- a/misc.go
+++ b/misc.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-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 (
diff --git a/peer.go b/peer.go
index ec411b2..9703b58 100644
--- a/peer.go
+++ b/peer.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/ratelimiter/ratelimiter.go b/ratelimiter/ratelimiter.go
index 006900a..1aa6813 100644
--- a/ratelimiter/ratelimiter.go
+++ b/ratelimiter/ratelimiter.go
@@ -1,9 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
 package ratelimiter
 
-/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
-
-/* This file contains a port of the rate-limiter from the linux kernel version */
-
 import (
 	"net"
 	"sync"
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 (
diff --git a/receive.go b/receive.go
index 7d35497..156ade5 100644
--- a/receive.go
+++ b/receive.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/replay.go b/replay.go
index 5d42860..8fab1d2 100644
--- a/replay.go
+++ b/replay.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
 
 /* 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 (
diff --git a/routing.go b/routing.go
index 2a2e237..77c9b1e 100644
--- a/routing.go
+++ b/routing.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/send.go b/send.go
index 5c6b350..24c7f32 100644
--- a/send.go
+++ b/send.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/signal.go b/signal.go
index 1505593..4d51bfa 100644
--- a/signal.go
+++ b/signal.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
 
 type Signal 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 (
diff --git a/timer.go b/timer.go
index 74e3a4e..aeab5d9 100644
--- a/timer.go
+++ b/timer.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/timers.go b/timers.go
index ba0d0e5..835191f 100644
--- a/timers.go
+++ b/timers.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.go b/trie.go
index 405ffc3..03f0722 100644
--- a/trie.go
+++ b/trie.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_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 (
diff --git a/tun.go b/tun.go
index 318772a..ec3ab47 100644
--- a/tun.go
+++ b/tun.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/tun_darwin.go b/tun_darwin.go
index d03ff48..a03347f 100644
--- a/tun_darwin.go
+++ b/tun_darwin.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/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 (
diff --git a/uapi.go b/uapi.go
index c795b73..a7ef662 100644
--- a/uapi.go
+++ b/uapi.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_darwin.go b/uapi_darwin.go
index 4cb4e62..954d720 100644
--- a/uapi_darwin.go
+++ b/uapi_darwin.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_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/warning_default.go b/warning_default.go
index 92d1b1d..8a0a448 100644
--- a/warning_default.go
+++ b/warning_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/warning_linux.go b/warning_linux.go
index d82805f..2ac7957 100644
--- a/warning_linux.go
+++ b/warning_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/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 (

From 0f322f83f5a920f89a9293e4dc48efc27e4acbac Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 4 May 2018 19:50:08 +0200
Subject: [PATCH 4/7] warning: put into main

---
 main.go            | 45 +++++++++++++++++++++++++++++++++++++++++----
 warning_default.go | 24 ------------------------
 warning_linux.go   | 44 --------------------------------------------
 3 files changed, 41 insertions(+), 72 deletions(-)
 delete mode 100644 warning_default.go
 delete mode 100644 warning_linux.go

diff --git a/main.go b/main.go
index 4b8299a..41231bf 100644
--- a/main.go
+++ b/main.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
+	"runtime"
 	"strconv"
 )
 
@@ -18,8 +19,8 @@ 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"
 )
 
@@ -28,9 +29,45 @@ func printUsage() {
 	fmt.Printf("%s [-f/--foreground] INTERFACE-NAME\n", os.Args[0])
 }
 
-func main() {
+func warning() {
+	shouldQuit := false
 
-	Warning()
+	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
 
diff --git a/warning_default.go b/warning_default.go
deleted file mode 100644
index 8a0a448..0000000
--- a/warning_default.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// +build !linux
-
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-package main
-
-import (
-	"fmt"
-	"os"
-)
-
-func Warning() {
-	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")
-	fmt.Fprintln(os.Stderr, "W                                                     G")
-	fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
-}
diff --git a/warning_linux.go b/warning_linux.go
deleted file mode 100644
index 2ac7957..0000000
--- a/warning_linux.go
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-package main
-
-import (
-	"fmt"
-	"os"
-)
-
-func Warning() {
-	shouldQuit := os.Getenv("WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD") != "1"
-
-	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")
-	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)
-	}
-}

From de7ecc571b9ea81d5cad97e339e84f8084352741 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 4 May 2018 21:11:38 +0200
Subject: [PATCH 5/7] tun: allow darwin to auto assign names

---
 main.go       | 22 +++++++++++++++-------
 tun_darwin.go |  8 +++++---
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/main.go b/main.go
index 41231bf..8562bf6 100644
--- a/main.go
+++ b/main.go
@@ -115,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) {
@@ -141,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)
diff --git a/tun_darwin.go b/tun_darwin.go
index a03347f..4d9b06d 100644
--- a/tun_darwin.go
+++ b/tun_darwin.go
@@ -46,9 +46,11 @@ var sockaddrCtlSize uintptr = 32
 
 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)

From ac898bb35afde34a383f72726c2818d082933e8d Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 4 May 2018 21:20:19 +0200
Subject: [PATCH 6/7] tun: print automatically assigned interface name to
 stdout

This way scripts know what process they just started.
---
 tun_darwin.go | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tun_darwin.go b/tun_darwin.go
index 4d9b06d..5514563 100644
--- a/tun_darwin.go
+++ b/tun_darwin.go
@@ -98,7 +98,13 @@ func CreateTUN(name string) (TUNDevice, error) {
 		return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
 	}
 
-	return CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
+	tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
+
+	if err == nil && name == "utun" {
+		fmt.Printf("OS assigned interface: %s\n", tun.(*NativeTun).name)
+	}
+
+	return tun, err
 }
 
 func CreateTUNFromFile(file *os.File) (TUNDevice, error) {

From e1de0f229a8f2cbfc4bb56230de885386a775fd6 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 4 May 2018 21:51:55 +0200
Subject: [PATCH 7/7] uapi: use kqueue for sock deletion on darwin

---
 main.go        |  4 ++++
 uapi_darwin.go | 44 ++++++++++++++++++++++++++++++++++++++------
 2 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/main.go b/main.go
index 8562bf6..e7e0488 100644
--- a/main.go
+++ b/main.go
@@ -227,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 {
diff --git a/uapi_darwin.go b/uapi_darwin.go
index 954d720..69b0e3d 100644
--- a/uapi_darwin.go
+++ b/uapi_darwin.go
@@ -12,7 +12,6 @@ import (
 	"net"
 	"os"
 	"path"
-	"time"
 )
 
 const (
@@ -28,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) {
@@ -43,7 +44,16 @@ 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 {
@@ -65,8 +75,6 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
 		connErr:  make(chan error, 1),
 	}
 
-	// watch for deletion of socket
-
 	socketPath := path.Join(
 		socketDirectory,
 		fmt.Sprintf(socketName, name),
@@ -74,12 +82,36 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
 
 	// watch for deletion of socket
 
+	uapi.kqueueFd, err = unix.Kqueue()
+	if err != nil {
+		return nil, err
+	}
+	uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0)
+	if err != nil {
+		unix.Close(uapi.kqueueFd)
+		return nil, err
+	}
+
 	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)