fake IFF_NO_PI on macOS

This commit is contained in:
Song Gao 2017-03-14 22:07:17 -07:00
parent ee9c96d609
commit 3a225b3c2e

View file

@ -5,7 +5,9 @@ package water
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"os" "os"
"sync"
"syscall" "syscall"
"unsafe" "unsafe"
) )
@ -112,12 +114,68 @@ func newTUN(string) (ifce *Interface, err error) {
} }
return &Interface{ return &Interface{
isTAP: false, isTAP: false,
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
ReadWriteCloser: os.NewFile(uintptr(fd), string(ifName.name[:])), ReadWriteCloser: &tunReadCloser{
f: os.NewFile(uintptr(fd), string(ifName.name[:])),
},
}, nil }, 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 {
f io.ReadWriteCloser
rMu sync.Mutex
rBuf []byte
wMu sync.Mutex
wBuf []byte
}
var _ io.ReadWriteCloser = (*tunReadCloser)(nil)
func (t *tunReadCloser) Read(to []byte) (int, error) {
t.rMu.Lock()
defer t.rMu.Unlock()
if cap(t.rBuf) < len(to)+4 {
t.rBuf = make([]byte, len(to)+4)
}
t.rBuf = t.rBuf[:len(to)+4]
n, err := t.f.Read(t.rBuf)
copy(to, t.rBuf[4:])
return n - 4, err
}
func (t *tunReadCloser) Write(from []byte) (int, error) {
t.wMu.Lock()
defer t.wMu.Unlock()
if cap(t.wBuf) < len(from)+4 {
t.wBuf = make([]byte, len(from)+4)
}
t.wBuf = t.wBuf[:len(from)+4]
t.wBuf[0] = 2 // Family: IP (2)
copy(t.wBuf[4:], from)
n, err := t.f.Write(t.wBuf)
return n - 4, err
}
func (t *tunReadCloser) Close() error {
// lock to make sure no read/write is in process.
t.rMu.Lock()
defer t.rMu.Unlock()
t.wMu.Lock()
defer t.wMu.Unlock()
return t.f.Close()
}
func newTAP(ifName string) (ifce *Interface, err error) { func newTAP(ifName string) (ifce *Interface, err error) {
return nil, errors.New("tap interface not implemented on this platform") return nil, errors.New("tap interface not implemented on this platform")
} }