Fixed TUN interface implementation os OS X

This commit is contained in:
Mathias Hall-Andersen 2017-09-03 18:10:06 +02:00
parent c24b883c01
commit 89d0045214
3 changed files with 91 additions and 30 deletions

View File

@ -14,8 +14,10 @@ import (
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"io" "io"
"net"
"os" "os"
"sync" "sync"
"time"
"unsafe" "unsafe"
) )
@ -34,6 +36,23 @@ type sockaddrCtl struct {
scReserved [5]uint32 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 var sockaddrCtlSize uintptr = 32
func CreateTUN(name string) (ifce TUNDevice, err error) { 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) return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err)
} }
device := &tunReadCloser{ device := &NativeTUN{
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
f: os.NewFile(uintptr(fd), string(ifName.name[:])), f: os.NewFile(uintptr(fd), string(ifName.name[:])),
mtu: 1500, 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 // set default MTU
err = device.setMTU(DefaultMTU) err = device.setMTU(DefaultMTU)
@ -123,23 +178,13 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
return device, err return device, err
} }
// tunReadCloser is a hack to work around the first 4 bytes "packet var _ io.ReadWriteCloser = (*NativeTUN)(nil)
// information" because there doesn't seem to be an IFF_NO_PI for darwin.
type tunReadCloser struct {
name string
f io.ReadWriteCloser
mtu int
rMu sync.Mutex func (t *NativeTUN) Events() chan TUNEvent {
rBuf []byte return t.events
wMu sync.Mutex
wBuf []byte
} }
var _ io.ReadWriteCloser = (*tunReadCloser)(nil) func (t *NativeTUN) Read(to []byte) (int, error) {
func (t *tunReadCloser) Read(to []byte) (int, error) {
t.rMu.Lock() t.rMu.Lock()
defer t.rMu.Unlock() defer t.rMu.Unlock()
@ -153,7 +198,7 @@ func (t *tunReadCloser) Read(to []byte) (int, error) {
return n - 4, err return n - 4, err
} }
func (t *tunReadCloser) Write(from []byte) (int, error) { func (t *NativeTUN) Write(from []byte) (int, error) {
if len(from) == 0 { if len(from) == 0 {
return 0, unix.EIO return 0, unix.EIO
@ -184,7 +229,7 @@ func (t *tunReadCloser) Write(from []byte) (int, error) {
return n - 4, err return n - 4, err
} }
func (t *tunReadCloser) Close() error { func (t *NativeTUN) Close() error {
// lock to make sure no read/write is in process. // lock to make sure no read/write is in process.
@ -197,11 +242,11 @@ func (t *tunReadCloser) Close() error {
return t.f.Close() return t.f.Close()
} }
func (t *tunReadCloser) Name() string { func (t *NativeTUN) Name() string {
return t.name return t.name
} }
func (t *tunReadCloser) setMTU(n int) error { func (t *NativeTUN) setMTU(n int) error {
// open datagram socket // open datagram socket
@ -238,7 +283,7 @@ func (t *tunReadCloser) setMTU(n int) error {
return nil return nil
} }
func (t *tunReadCloser) MTU() (int, error) { func (t *NativeTUN) MTU() (int, error) {
// open datagram socket // open datagram socket

View File

@ -2,11 +2,22 @@ package main
import ( import (
"fmt" "fmt"
"golang.org/x/sys/unix"
"net" "net"
"os" "os"
"path"
"time" "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 { type UAPIListener struct {
listener net.Listener // unix socket listener listener net.Listener // unix socket listener
connNew chan net.Conn connNew chan net.Conn
@ -35,9 +46,20 @@ func (l *UAPIListener) Addr() net.Addr {
func NewUAPIListener(name string) (net.Listener, error) { 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 // 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) listener, err := net.Listen("unix", socketPath)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -18,12 +18,6 @@ const (
socketName = "%s.sock" 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 { type UAPIListener struct {
listener net.Listener // unix socket listener listener net.Listener // unix socket listener
connNew chan net.Conn connNew chan net.Conn