Skip to content

Commit

Permalink
osxtuntap support
Browse files Browse the repository at this point in the history
  • Loading branch information
Yifan Gu authored and songgao committed Jun 23, 2019
1 parent 6ad6ede commit aa5a321
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
15 changes: 15 additions & 0 deletions params_darwin.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
package water

const (
// SystemDriver refers to the default P2P driver
SystemDriver = 0
// TunTapOSXDriver refers to the third-party tuntaposx driver
// see https://sourceforge.net/p/tuntaposx
TunTapOSXDriver = 1
)

// PlatformSpecificParams defines parameters in Config that are specific to
// macOS. A zero-value of such type is valid, yielding an interface
// with OS defined name.
// Currently it is not possible to set the interface name in macOS.
type PlatformSpecificParams struct {
// Name is the name for the interface to be used.
// e.g. "tap0"
// Only valid if using TunTapOSXDriver.
Name string
// Driver should be set if an alternative driver is desired
// e.g. TunTapOSXDriver
Driver int
}

func defaultPlatformSpecificParams() PlatformSpecificParams {
Expand Down
61 changes: 59 additions & 2 deletions syscalls_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"strings"
"sync"
"syscall"
"unsafe"
Expand Down Expand Up @@ -60,8 +61,13 @@ type sockaddrCtl struct {
var sockaddrCtlSize uintptr = 32

func openDev(config Config) (ifce *Interface, err error) {
if config.Driver == TunTapOSXDriver {
return openDevTunTapOSX(config)
} else if config.Driver != SystemDriver {
return nil, errors.New("unrecognized driver")
}
if config.DeviceType != TUN {
return nil, errors.New("only tun is implemented on this platform")
return nil, errors.New("only tun is implemented for SystemDriver, use TunTapOSXDriver for tap")
}
var fd int
// Supposed to be socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), but ...
Expand All @@ -83,7 +89,7 @@ func openDev(config Config) (ifce *Interface, err error) {

if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(appleCTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo))); errno != 0 {
err = errno
return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOTL, ...): %v", err)
return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
}

addrP := unsafe.Pointer(&sockaddrCtl{
Expand Down Expand Up @@ -127,6 +133,57 @@ func openDev(config Config) (ifce *Interface, err error) {
}, nil
}

// openDevTunTapOSX opens tun / tap device, assuming tuntaposx is installed
func openDevTunTapOSX(config Config) (ifce *Interface, err error) {
var fd int
var socketFD int

if config.DeviceType == TAP && !strings.HasPrefix(config.Name, "tap") {
return nil, errors.New("device name does not start with tap when creating a tap device")
} else if config.DeviceType == TUN && !strings.HasPrefix(config.Name, "tun") {
return nil, errors.New("device name does not start with tun when creating a tun device")
} else if config.DeviceType != TAP && config.DeviceType != TUN {
return nil, errors.New("unsupported DeviceType")
}
if len(config.Name) >= 15 {
return nil, errors.New("device name is too long")
}

if fd, err = syscall.Open(
"/dev/"+config.Name, os.O_RDWR|syscall.O_NONBLOCK, 0); err != nil {
return nil, err
}
// Note that we are not setting NONBLOCK on the fd itself since it breaks tuntaposx
// see https://sourceforge.net/p/tuntaposx/bugs/6/

// create socket so we can do SIO ioctls, we are not using it afterwards
if socketFD, err = syscall.Socket(syscall.AF_SYSTEM, syscall.SOCK_DGRAM, 2); err != nil {
return nil, fmt.Errorf("error in syscall.Socket: %v", err)
}
var ifReq = &struct {
ifName [16]byte
ifruFlags int16
pad [16]byte
}{}
copy(ifReq.ifName[:], []byte(config.Name))
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(socketFD), uintptr(syscall.SIOCGIFFLAGS), uintptr(unsafe.Pointer(ifReq))); errno != 0 {
err = errno
return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
}
ifReq.ifruFlags |= syscall.IFF_RUNNING | syscall.IFF_UP
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(socketFD), uintptr(syscall.SIOCSIFFLAGS), uintptr(unsafe.Pointer(ifReq))); errno != 0 {
err = errno
return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOCTL, ...): %v", err)
}
syscall.Close(socketFD)

return &Interface{
isTAP: config.DeviceType == TAP,
ReadWriteCloser: os.NewFile(uintptr(fd), "tun"),
name: config.Name,
}, nil
}

// 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 {
Expand Down

0 comments on commit aa5a321

Please sign in to comment.