]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
Start to dust off Darwin
authorJason A. Donenfeld <Jason@zx2c4.com>
Thu, 3 May 2018 02:49:35 +0000 (04:49 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Thu, 3 May 2018 12:55:10 +0000 (14:55 +0200)
daemon.go [moved from daemon_linux.go with 55% similarity]
daemon_darwin.go [deleted file]
daemon_windows.go [deleted file]
main.go
tun_darwin.go
uapi_darwin.go
warning_default.go [new file with mode: 0644]
warning_linux.go [new file with mode: 0644]

similarity index 55%
rename from daemon_linux.go
rename to daemon.go
index e1aaede3806624ea1a5c84cd3bdf4fa13d38734f..e2ded877c86b9d55a8843ab777d4637552c9a9b6 100644 (file)
+++ 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 (file)
index 913af0e..0000000
+++ /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 (file)
index 527718a..0000000
+++ /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 7742eef04bd9421cbb5c3a4011de0709f754c4f3..3358469888a1c16c253cd060314540a7cfb8310e 100644 (file)
--- a/main.go
+++ b/main.go
@@ -25,6 +25,8 @@ func printUsage() {
 
 func main() {
 
+       Warning()
+
        // parse arguments
 
        var foreground bool
index 87f6af6b20e7e5f154b0cb8d2bad5c959e7d4d07..d03ff485f27ce0b90b502960acd23f7d3ec39a6e 100644 (file)
@@ -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)
-       }
-
-       // read (new) name of interface
-
-       var ifName struct {
-               name [16]byte
+               return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
        }
-       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 CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
+}
 
-       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]
+       return n - 4, err
+}
 
-       // determine the IP Family for the NULL L2 Header
+func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
 
-       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.")
-       }
+       // reserve space for header
 
-       copy(t.wBuf[4:], from)
+       buff = buff[offset-4:]
 
-       n, err := t.f.Write(t.wBuf)
-       return n - 4, err
-}
-
-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 +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
index 2850184149516a753b128dfcb18700b94be463b4..4cb4e625b4b3274687b4626e7b9387715e65139b 100644 (file)
@@ -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
-
-       err := os.MkdirAll(socketDirectory, 077)
-       if err != nil && !os.IsExist(err) {
-               return nil, err
-       }
-
-       // open UNIX socket
+       // wrap file in listener
 
-       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 (file)
index 0000000..92d1b1d
--- /dev/null
@@ -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 (file)
index 0000000..d82805f
--- /dev/null
@@ -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)
+       }
+}