Fixed TUN interface implementation os OS X
This commit is contained in:
		
							parent
							
								
									c24b883c01
								
							
						
					
					
						commit
						89d0045214
					
				
					 3 changed files with 91 additions and 30 deletions
				
			
		|  | @ -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