]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
Rework freebsd support
authorJason A. Donenfeld <Jason@zx2c4.com>
Mon, 21 May 2018 15:27:18 +0000 (17:27 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Mon, 21 May 2018 16:48:48 +0000 (18:48 +0200)
README.md
conn_default.go
rwcancel/select_default.go
tun_darwin.go
tun_freebsd.go
tun_freebsd_386.go [deleted file]
tun_freebsd_amd64.go [deleted file]
tun_linux.go
uapi_bsd.go [moved from uapi_darwin.go with 97% similarity]
uapi_freebsd.go [deleted file]

index 499fcc57697cef31eabba47b7949c3d3bbd1f3da..56e4622df002493900b6cef4c13cba2a4fbda0b4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ It is currently a work in progress to strip out the beginnings of an experiment
 
 ### FreeBSD
 
-Work in progress, but nothing yet to share.
+This will run on FreeBSD.
 
 ## Building
 
index da6fa3dd0c0224851fdea38ea46cf88c556028d5..9f1e0b02e4a324360adf26ee447c44d55350cdba 100644 (file)
@@ -9,7 +9,9 @@
 package main
 
 import (
+       "golang.org/x/sys/unix"
        "net"
+       "runtime"
 )
 
 /* This code is meant to be a temporary solution
@@ -138,6 +140,35 @@ func (bind *NativeBind) Send(buff []byte, endpoint Endpoint) error {
        return err
 }
 
-func (bind *NativeBind) SetMark(_ uint32) error {
+func (bind *NativeBind) SetMark(mark uint32) error {
+       if runtime.GOOS == "freebsd" {
+               fd4, err1 := bind.ipv4.SyscallConn()
+               fd6, err2 := bind.ipv6.SyscallConn()
+               if err1 != nil {
+                       return err1
+               }
+               if err2 != nil {
+                       return err2
+               }
+               err3 := fd4.Control(func(fd uintptr) {
+                       err1 = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, 0x1014 /* unix.SO_SETFIB */, int(mark))
+               })
+               err4 := fd6.Control(func(fd uintptr) {
+                       err2 = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, 0x1014 /* unix.SO_SETFIB */, int(mark))
+               })
+               if err1 != nil {
+                       return err1
+               }
+               if err2 != nil {
+                       return err2
+               }
+               if err3 != nil {
+                       return err3
+               }
+               if err4 != nil {
+                       return err4
+               }
+               return nil
+       }
        return nil
 }
index 302a6185d71fdb869681b94bbe728c27f01bca58..d37a5363bce5f6a21ee62e3b599ab1446b977f38 100644 (file)
@@ -1,10 +1,10 @@
+// +build !linux
+
 /* SPDX-License-Identifier: GPL-2.0
  *
  * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  */
 
-// +build !linux
-
 package rwcancel
 
 import "golang.org/x/sys/unix"
index b8afdfd6e64f073b9f6d2afbc4b02499dc4b9d85..ef84967bb93bcc954a86452e6655395edf64495c 100644 (file)
@@ -34,8 +34,6 @@ type sockaddrCtl struct {
        scReserved [5]uint32
 }
 
-// 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 {
        name        string
        fd          *os.File
@@ -67,7 +65,7 @@ func (tun *NativeTun) RoutineRouteListener(tunIfindex int) {
                        continue
                }
 
-               if data[3 /* type */] != 0xe /* RTM_IFINFO */ {
+               if data[3 /* type */] != unix.RTM_IFINFO {
                        continue
                }
                ifindex := int(*(*uint16)(unsafe.Pointer(&data[12 /* ifindex */])))
@@ -347,7 +345,7 @@ func (tun *NativeTun) setMTU(n int) error {
        )
 
        if errno != 0 {
-               return fmt.Errorf("Failed to set MTU on %s", tun.name)
+               return fmt.Errorf("failed to set MTU on %s", tun.name)
        }
 
        return nil
@@ -380,7 +378,7 @@ func (tun *NativeTun) MTU() (int, error) {
                uintptr(unsafe.Pointer(&ifr[0])),
        )
        if errno != 0 {
-               return 0, fmt.Errorf("Failed to get MTU on %s", tun.name)
+               return 0, fmt.Errorf("failed to get MTU on %s", tun.name)
        }
 
        // convert result to signed 32-bit int
index e83b8efd5d7e26500b3bb9ba899dbc22cafa0502..e2ec5116337046ac05c69941179a58dce3354cd9 100644 (file)
@@ -12,11 +12,8 @@ import (
        "fmt"
        "golang.org/x/net/ipv6"
        "golang.org/x/sys/unix"
-       "io/ioutil"
        "net"
        "os"
-       "path/filepath"
-       "time"
        "unsafe"
 )
 
@@ -29,38 +26,93 @@ const _TUNSIFPID = 0x2000745f
 // Iface status string max len
 const _IFSTATMAX = 800
 
+const SIZEOF_UINTPTR = 4 << (^uintptr(0) >> 32 & 1)
+
+// structure for iface requests with a pointer
+type ifreq_ptr struct {
+       Name [unix.IFNAMSIZ]byte
+       Data uintptr
+       Pad0 [24 - SIZEOF_UINTPTR]byte
+}
+
 // Structure for iface mtu get/set ioctls
 type ifreq_mtu struct {
-       Name [_IFNAMESIZ]byte
+       Name [unix.IFNAMSIZ]byte
        MTU  uint32
        Pad0 [12]byte
 }
 
 // Structure for interface status request ioctl
 type ifstat struct {
-       IfsName [_IFNAMESIZ]byte
+       IfsName [unix.IFNAMSIZ]byte
        Ascii   [_IFSTATMAX]byte
 }
 
-// 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 {
-       name                    string
-       fd                      *os.File
-       rwcancel                *rwcancel.RWCancel
-       mtu                     int
-       events                  chan TUNEvent
-       errors                  chan error
-       statusListenersShutdown chan struct{}
+       name        string
+       fd          *os.File
+       rwcancel    *rwcancel.RWCancel
+       events      chan TUNEvent
+       errors      chan error
+       routeSocket int
+}
+
+func (tun *NativeTun) RoutineRouteListener(tunIfindex int) {
+       var (
+               statusUp  bool
+               statusMTU int
+       )
+
+       defer close(tun.events)
+
+       data := make([]byte, os.Getpagesize())
+       for {
+               n, err := unix.Read(tun.routeSocket, data)
+               if err != nil {
+                       tun.errors <- err
+                       return
+               }
+
+               if n < 14 {
+                       continue
+               }
+
+               if data[3 /* type */] != unix.RTM_IFINFO {
+                       continue
+               }
+               ifindex := int(*(*uint16)(unsafe.Pointer(&data[12 /* ifindex */])))
+               if ifindex != tunIfindex {
+                       continue
+               }
+
+               iface, err := net.InterfaceByIndex(ifindex)
+               if err != nil {
+                       tun.errors <- err
+                       return
+               }
+
+               // Up / Down event
+               up := (iface.Flags & net.FlagUp) != 0
+               if up != statusUp && up {
+                       tun.events <- TUNEventUp
+               }
+               if up != statusUp && !up {
+                       tun.events <- TUNEventDown
+               }
+               statusUp = up
+
+               // MTU changes
+               if iface.MTU != statusMTU {
+                       tun.events <- TUNEventMTUUpdate
+               }
+               statusMTU = iface.MTU
+       }
 }
 
-// Figure out the interface name for an open tun device file descriptor
-func TunIfaceName(f *os.File) (string, error) {
+func tunName(fd uintptr) (string, error) {
        //Terrible hack to make up for freebsd not having a TUNGIFNAME
 
-       fd := f.Fd()
        //First, make sure the tun pid matches this proc's pid
-
        _, _, errno := unix.Syscall(
                unix.SYS_IOCTL,
                uintptr(fd),
@@ -69,7 +121,7 @@ func TunIfaceName(f *os.File) (string, error) {
        )
 
        if errno != 0 {
-               return "", fmt.Errorf("Failed to set tun device PID: %s", errno.Error())
+               return "", fmt.Errorf("failed to set tun device PID: %s", errno.Error())
        }
 
        // Open iface control socket
@@ -80,12 +132,12 @@ func TunIfaceName(f *os.File) (string, error) {
                0,
        )
 
-       defer unix.Close(confd)
-
        if err != nil {
                return "", err
        }
 
+       defer unix.Close(confd)
+
        procPid := os.Getpid()
 
        //Try to find interface with matching PID
@@ -97,8 +149,7 @@ func TunIfaceName(f *os.File) (string, error) {
 
                // Structs for getting data in and out of SIOCGIFSTATUS ioctl
                var ifstatus ifstat
-               ifname := iface.Name
-               copy(ifstatus.IfsName[:], ifname)
+               copy(ifstatus.IfsName[:], iface.Name)
 
                // Make the syscall to get the status string
                _, _, errno := unix.Syscall(
@@ -117,30 +168,26 @@ func TunIfaceName(f *os.File) (string, error) {
                if i < 1 {
                        continue
                }
-               if i != -1 {
-                       nullStr = nullStr[:i]
-               }
-               statStr := string(nullStr)
+               statStr := string(nullStr[:i])
                var pidNum int = 0
 
                // Finally get the owning PID
                // Format string taken from sys/net/if_tun.c
                _, err := fmt.Sscanf(statStr, "\tOpened by PID %d\n", &pidNum)
                if err != nil {
-                       return "", err
+                       continue
                }
 
                if pidNum == procPid {
-                       return ifname, nil
+                       return iface.Name, nil
                }
-
        }
 
        return "", nil
 }
 
 // Destroy a named system interface
-func DestroyIface(name string) error {
+func tunDestroy(name string) error {
        // open control socket
        var fd int
 
@@ -168,21 +215,21 @@ func DestroyIface(name string) error {
        )
 
        if errno != 0 {
-               return fmt.Errorf("Failed to destroy interface %s: %s", name, errno.Error())
+               return fmt.Errorf("failed to destroy interface %s: %s", name, errno.Error())
        }
 
        return nil
 }
 
 func CreateTUN(name string) (TUNDevice, error) {
-       if len(name) > _IFNAMESIZ-1 {
-               return nil, errors.New("Interface name too long")
+       if len(name) > unix.IFNAMSIZ-1 {
+               return nil, errors.New("interface name too long")
        }
 
        // See if interface already exists
        iface, _ := net.InterfaceByName(name)
        if iface != nil {
-               return nil, fmt.Errorf("Interface %s already exists", name)
+               return nil, fmt.Errorf("interface %s already exists", name)
        }
 
        tunfile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0)
@@ -190,16 +237,13 @@ func CreateTUN(name string) (TUNDevice, error) {
        if err != nil {
                return nil, err
        }
-
-       nameif, err := TunIfaceName(tunfile)
-
+       tunfd := tunfile.Fd()
+       assignedName, err := tunName(tunfd)
        if err != nil {
                tunfile.Close()
                return nil, err
        }
 
-       tunfd := tunfile.Fd()
-
        // Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet
        ifheadmode := 1
        _, _, errno := unix.Syscall(
@@ -210,11 +254,10 @@ func CreateTUN(name string) (TUNDevice, error) {
        )
 
        if errno != 0 {
-               return nil, fmt.Errorf("Error %s", errno.Error())
+               return nil, fmt.Errorf("error %s", errno.Error())
        }
 
-       /* Set TUN iface to broadcast mode. TUN inferfaces on freebsd come up
-        * point to point by default */
+       // Set TUN iface to broadcast mode. TUN inferfaces on freebsd come up in point to point by default
        ifmodemode := unix.IFF_BROADCAST
        _, _, errno = unix.Syscall(
                unix.SYS_IOCTL,
@@ -224,12 +267,13 @@ func CreateTUN(name string) (TUNDevice, error) {
        )
 
        if errno != 0 {
-               return nil, fmt.Errorf("Error %s", errno.Error())
+               return nil, fmt.Errorf("error %s", errno.Error())
        }
 
        // Rename tun interface
+
        // Open control socket
-       ctfd, err := unix.Socket(
+       confd, err := unix.Socket(
                unix.AF_INET,
                unix.SOCK_DGRAM,
                0,
@@ -239,27 +283,27 @@ func CreateTUN(name string) (TUNDevice, error) {
                return nil, err
        }
 
-       defer unix.Close(ctfd)
+       defer unix.Close(confd)
 
        // set up struct for iface rename
-       var newnp [_IFNAMESIZ]byte
+       var newnp [unix.IFNAMSIZ]byte
        copy(newnp[:], name)
 
        var ifr ifreq_ptr
-       copy(ifr.Name[:], nameif)
+       copy(ifr.Name[:], assignedName)
        ifr.Data = uintptr(unsafe.Pointer(&newnp[0]))
 
        //do actual ioctl to rename iface
        _, _, errno = unix.Syscall(
                unix.SYS_IOCTL,
-               uintptr(ctfd),
+               uintptr(confd),
                uintptr(unix.SIOCSIFNAME),
                uintptr(unsafe.Pointer(&ifr)),
        )
        if errno != 0 {
                tunfile.Close()
-               DestroyIface(name)
-               return nil, fmt.Errorf("Failed to rename %s to %s: %s", nameif, name, errno.Error())
+               tunDestroy(name)
+               return nil, fmt.Errorf("failed to rename %s to %s: %s", assignedName, name, errno.Error())
        }
 
        tun, err := CreateTUNFromFile(tunfile)
@@ -267,29 +311,34 @@ func CreateTUN(name string) (TUNDevice, error) {
        if err != nil {
                return nil, err
        }
-
-       if err == nil && name == "tun" {
-               fname := os.Getenv("WG_FREEBSD_TUN_NAME_FILE")
-               if fname != "" {
-                       os.MkdirAll(filepath.Dir(fname), 0700)
-                       ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
-               }
-       }
-
        return tun, err
 }
 
 func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
 
        tun := &NativeTun{
-               fd:                      file,
-               mtu:                     1500,
-               events:                  make(chan TUNEvent, 10),
-               errors:                  make(chan error, 1),
-               statusListenersShutdown: make(chan struct{}),
+               fd:     file,
+               events: make(chan TUNEvent, 10),
+               errors: make(chan error, 1),
        }
 
-       _, err := tun.Name()
+       name, err := tun.Name()
+       if err != nil {
+               tun.fd.Close()
+               return nil, err
+       }
+
+       tunIfindex, err := func() (int, error) {
+               iface, err := net.InterfaceByName(name)
+               if err != nil {
+                       return -1, err
+               }
+               return iface.Index, nil
+       }()
+       if err != nil {
+               tun.fd.Close()
+               return nil, err
+       }
 
        if err != nil {
                tun.fd.Close()
@@ -302,43 +351,13 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
                return nil, err
        }
 
-       // TODO: Fix this very naive implementation
-       go func(tun *NativeTun) {
-               var (
-                       statusUp  bool
-                       statusMTU int
-               )
+       tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
+       if err != nil {
+               tun.fd.Close()
+               return nil, err
+       }
 
-               for {
-                       intr, err := net.InterfaceByName(tun.name)
-                       if err != nil {
-                               tun.errors <- err
-                               return
-                       }
-
-                       // Up / Down event
-                       up := (intr.Flags & net.FlagUp) != 0
-                       if up != statusUp && up {
-                               tun.events <- TUNEventUp
-                       }
-                       if up != statusUp && !up {
-                               tun.events <- TUNEventDown
-                       }
-                       statusUp = up
-
-                       // MTU changes
-                       if intr.MTU != statusMTU {
-                               tun.events <- TUNEventMTUUpdate
-                       }
-                       statusMTU = intr.MTU
-
-                       select {
-                       case <-time.After(time.Second / 10):
-                       case <-tun.statusListenersShutdown:
-                               return
-                       }
-               }
-       }(tun)
+       go tun.RoutineRouteListener(tunIfindex)
 
        // set default MTU
        err = tun.setMTU(DefaultMTU)
@@ -351,7 +370,7 @@ func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
 }
 
 func (tun *NativeTun) Name() (string, error) {
-       name, err := TunIfaceName(tun.fd)
+       name, err := tunName(tun.fd.Fd())
        if err != nil {
                return "", err
        }
@@ -417,18 +436,28 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
 }
 
 func (tun *NativeTun) Close() error {
-       close(tun.statusListenersShutdown)
+       var err4 error
        err1 := tun.rwcancel.Cancel()
        err2 := tun.fd.Close()
-       err3 := DestroyIface(tun.name)
-       close(tun.events)
+       err3 := tunDestroy(tun.name)
+       if tun.routeSocket != -1 {
+               // Surprisingly, on FreeBSD, simply closing a route socket is enough to unblock it.
+               // We don't even need to call shutdown, or use a rwcancel. TODO: CONFIRM THIS CLAIM. IT WAS TRUE ON DARWIN BUT...
+               err4 = unix.Close(tun.routeSocket)
+               tun.routeSocket = -1
+       } else if tun.events != nil {
+               close(tun.events)
+       }
        if err1 != nil {
                return err1
        }
        if err2 != nil {
                return err2
        }
-       return err3
+       if err3 != nil {
+               return err3
+       }
+       return err4
 }
 
 func (tun *NativeTun) setMTU(n int) error {
@@ -462,7 +491,7 @@ func (tun *NativeTun) setMTU(n int) error {
        )
 
        if errno != 0 {
-               return fmt.Errorf("Failed to set MTU on %s", tun.name)
+               return fmt.Errorf("failed to set MTU on %s", tun.name)
        }
 
        return nil
@@ -494,7 +523,7 @@ func (tun *NativeTun) MTU() (int, error) {
                uintptr(unsafe.Pointer(&ifr)),
        )
        if errno != 0 {
-               return 0, fmt.Errorf("Failed to get MTU on %s", tun.name)
+               return 0, fmt.Errorf("failed to get MTU on %s", tun.name)
        }
 
        // convert result to signed 32-bit int
diff --git a/tun_freebsd_386.go b/tun_freebsd_386.go
deleted file mode 100644 (file)
index 13e9d95..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-/* Types to deal with FreeBSD fdiogname ioctl for determining tun device name */
-
-package main
-
-// Iface name max len
-const _IFNAMESIZ = 16
-
-// structure for iface requests with a pointer
-type ifreq_ptr struct {
-       Name [_IFNAMESIZ]byte
-       Data uintptr
-       Pad0 [20]byte
-}
diff --git a/tun_freebsd_amd64.go b/tun_freebsd_amd64.go
deleted file mode 100644 (file)
index 6b08caf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-/* Types to deal with FreeBSD fdiogname ioctl for determining tun device name */
-
-package main
-
-// Iface name max len
-const _IFNAMESIZ = 16
-
-// structure for iface requests with a pointer
-type ifreq_ptr struct {
-       Name [_IFNAMESIZ]byte
-       Data uintptr
-       Pad0 [16]byte
-}
index 629a5eca8bccc639fb607f6bc85d57298081335e..b43ded80d7cf3aa06a8730231a05c16bab652507 100644 (file)
@@ -227,7 +227,7 @@ func (tun *NativeTun) setMTU(n int) error {
        )
 
        if errno != 0 {
-               return errors.New("Failed to set MTU of TUN device")
+               return errors.New("failed to set MTU of TUN device")
        }
 
        return nil
@@ -260,7 +260,7 @@ func (tun *NativeTun) MTU() (int, error) {
                uintptr(unsafe.Pointer(&ifr[0])),
        )
        if errno != 0 {
-               return 0, errors.New("Failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
+               return 0, errors.New("failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
        }
 
        // convert result to signed 32-bit int
@@ -282,7 +282,7 @@ func (tun *NativeTun) Name() (string, error) {
                uintptr(unsafe.Pointer(&ifr[0])),
        )
        if errno != 0 {
-               return "", errors.New("Failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10))
+               return "", errors.New("failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10))
        }
        nullStr := ifr[:]
        i := bytes.IndexByte(nullStr, 0)
similarity index 97%
rename from uapi_darwin.go
rename to uapi_bsd.go
index 228021f071534b407e48738f37b90d8316136d53..5f323cb9eb087c41f2923a2900179cd3201a4447 100644 (file)
@@ -1,3 +1,5 @@
+// +build darwin freebsd
+
 /* SPDX-License-Identifier: GPL-2.0
  *
  * Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
@@ -91,7 +93,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
        if err != nil {
                return nil, err
        }
-       uapi.keventFd, err = unix.Open(socketDirectory, unix.O_EVTONLY, 0)
+       uapi.keventFd, err = unix.Open(socketDirectory, unix.O_RDONLY, 0)
        if err != nil {
                unix.Close(uapi.kqueueFd)
                return nil, err
diff --git a/uapi_freebsd.go b/uapi_freebsd.go
deleted file mode 100644 (file)
index 6a8fe8d..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/* 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"
-)
-
-const (
-       ipcErrorIO        = -int64(unix.EIO)
-       ipcErrorProtocol  = -int64(unix.EPROTO)
-       ipcErrorInvalid   = -int64(unix.EINVAL)
-       ipcErrorPortInUse = -int64(unix.EADDRINUSE)
-       socketDirectory   = "/var/run/wireguard"
-       socketName        = "%s.sock"
-)
-
-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) {
-       for {
-               select {
-               case conn := <-l.connNew:
-                       return conn, nil
-
-               case err := <-l.connErr:
-                       return nil, err
-               }
-       }
-}
-
-func (l *UAPIListener) Close() error {
-       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 l.listener.Addr()
-}
-
-func UAPIListen(name string, file *os.File) (net.Listener, error) {
-
-       // wrap file in listener
-
-       listener, err := net.FileListener(file)
-       if err != nil {
-               return nil, err
-       }
-
-       uapi := &UAPIListener{
-               listener: listener,
-               connNew:  make(chan net.Conn, 1),
-               connErr:  make(chan error, 1),
-       }
-
-       if unixListener, ok := listener.(*net.UnixListener); ok {
-               unixListener.SetUnlinkOnClose(true)
-       }
-
-       socketPath := path.Join(
-               socketDirectory,
-               fmt.Sprintf(socketName, name),
-       )
-
-       // watch for deletion of socket
-
-       uapi.kqueueFd, err = unix.Kqueue()
-       if err != nil {
-               return nil, err
-       }
-       // TODO: Double check socket deletion logic port from MacOS
-       uapi.keventFd, err = unix.Open(socketDirectory, unix.O_RDONLY, 0)
-       if err != nil {
-               unix.Close(uapi.kqueueFd)
-               return nil, err
-       }
-
-       go func(l *UAPIListener) {
-               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 {
-                               if kerr != nil {
-                                       l.connErr <- kerr
-                               } else {
-                                       l.connErr <- errors.New("kqueue returned empty")
-                               }
-                               return
-                       }
-                       n, kerr = unix.Kevent(uapi.kqueueFd, []unix.Kevent_t{event}, events, nil)
-               }
-       }(uapi)
-
-       // watch for new connections
-
-       go func(l *UAPIListener) {
-               for {
-                       conn, err := l.listener.Accept()
-                       if err != nil {
-                               l.connErr <- err
-                               break
-                       }
-                       l.connNew <- conn
-               }
-       }(uapi)
-
-       return uapi, nil
-}
-
-func UAPIOpen(name string) (*os.File, error) {
-
-       // check if path exist
-
-       err := os.MkdirAll(socketDirectory, 0700)
-       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()
-}