Fixed TUN interface implementation os OS X
This commit is contained in:
parent
c24b883c01
commit
89d0045214
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue