diff --git a/src/tun_darwin.go b/src/tun_darwin.go index 146817d..87f6af6 100644 --- a/src/tun_darwin.go +++ b/src/tun_darwin.go @@ -14,8 +14,10 @@ import ( "golang.org/x/net/ipv6" "golang.org/x/sys/unix" "io" + "net" "os" "sync" + "time" "unsafe" ) @@ -34,6 +36,23 @@ 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 + f io.ReadWriteCloser + 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) { @@ -110,12 +129,48 @@ func CreateTUN(name string) (ifce TUNDevice, err error) { return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err) } - device := &tunReadCloser{ - name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), - f: os.NewFile(uintptr(fd), string(ifName.name[:])), - mtu: 1500, + device := &NativeTUN{ + name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), + f: os.NewFile(uintptr(fd), string(ifName.name[:])), + mtu: 1500, + events: make(chan TUNEvent, 10), + errors: make(chan error, 1), } + // start listener + + go func(native *NativeTUN) { + // TODO: Fix this very niave implementation + var ( + statusUp bool + statusMTU int + ) + + for ; ; time.Sleep(time.Second) { + intr, err := net.InterfaceByName(device.name) + if err != nil { + native.errors <- err + return + } + + // Up / Down event + up := (intr.Flags & net.FlagUp) != 0 + if up != statusUp && up { + native.events <- TUNEventUp + } + if up != statusUp && !up { + native.events <- TUNEventDown + } + statusUp = up + + // MTU changes + if intr.MTU != statusMTU { + native.events <- TUNEventMTUUpdate + } + statusMTU = intr.MTU + } + }(device) + // set default MTU err = device.setMTU(DefaultMTU) @@ -123,23 +178,13 @@ func CreateTUN(name string) (ifce TUNDevice, err error) { return device, err } -// tunReadCloser 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 tunReadCloser struct { - name string - f io.ReadWriteCloser - mtu int +var _ io.ReadWriteCloser = (*NativeTUN)(nil) - rMu sync.Mutex - rBuf []byte - - wMu sync.Mutex - wBuf []byte +func (t *NativeTUN) Events() chan TUNEvent { + return t.events } -var _ io.ReadWriteCloser = (*tunReadCloser)(nil) - -func (t *tunReadCloser) Read(to []byte) (int, error) { +func (t *NativeTUN) Read(to []byte) (int, error) { t.rMu.Lock() defer t.rMu.Unlock() @@ -153,7 +198,7 @@ func (t *tunReadCloser) Read(to []byte) (int, error) { return n - 4, err } -func (t *tunReadCloser) Write(from []byte) (int, error) { +func (t *NativeTUN) Write(from []byte) (int, error) { if len(from) == 0 { return 0, unix.EIO @@ -184,7 +229,7 @@ func (t *tunReadCloser) Write(from []byte) (int, error) { return n - 4, err } -func (t *tunReadCloser) Close() error { +func (t *NativeTUN) Close() error { // lock to make sure no read/write is in process. @@ -197,11 +242,11 @@ func (t *tunReadCloser) Close() error { return t.f.Close() } -func (t *tunReadCloser) Name() string { +func (t *NativeTUN) Name() string { return t.name } -func (t *tunReadCloser) setMTU(n int) error { +func (t *NativeTUN) setMTU(n int) error { // open datagram socket @@ -238,7 +283,7 @@ func (t *tunReadCloser) setMTU(n int) error { return nil } -func (t *tunReadCloser) MTU() (int, error) { +func (t *NativeTUN) MTU() (int, error) { // open datagram socket diff --git a/src/uapi_darwin.go b/src/uapi_darwin.go index 9eee53c..13e5c4f 100644 --- a/src/uapi_darwin.go +++ b/src/uapi_darwin.go @@ -2,11 +2,22 @@ package main import ( "fmt" + "golang.org/x/sys/unix" "net" "os" + "path" "time" ) +const ( + ipcErrorIO = -int64(unix.EIO) + ipcErrorNotDefined = -int64(unix.ENODEV) + ipcErrorProtocol = -int64(unix.EPROTO) + ipcErrorInvalid = -int64(unix.EINVAL) + socketDirectory = "/var/run/wireguard" + socketName = "%s.sock" +) + type UAPIListener struct { listener net.Listener // unix socket listener connNew chan net.Conn @@ -35,9 +46,20 @@ func (l *UAPIListener) Addr() net.Addr { func NewUAPIListener(name string) (net.Listener, error) { + // check if path exist + + err := os.MkdirAll(socketDirectory, 077) + if err != nil && !os.IsExist(err) { + return nil, err + } + // open UNIX socket - socketPath := fmt.Sprintf("/var/run/wireguard/%s.sock", name) + socketPath := path.Join( + socketDirectory, + fmt.Sprintf(socketName, name), + ) + listener, err := net.Listen("unix", socketPath) if err != nil { return nil, err diff --git a/src/uapi_linux.go b/src/uapi_linux.go index b5dd663..db4f040 100644 --- a/src/uapi_linux.go +++ b/src/uapi_linux.go @@ -18,12 +18,6 @@ const ( socketName = "%s.sock" ) -/* TODO: - * This code can be improved by using fsnotify once: - * https://github.com/fsnotify/fsnotify/pull/205 - * Is merged - */ - type UAPIListener struct { listener net.Listener // unix socket listener connNew chan net.Conn