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/sys/unix" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
|  | @ -34,6 +36,23 @@ type sockaddrCtl struct { | |||
| 	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 | ||||
| 
 | ||||
| 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) | ||||
| 	} | ||||
| 
 | ||||
| 	device := &tunReadCloser{ | ||||
| 		name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), | ||||
| 		f:    os.NewFile(uintptr(fd), string(ifName.name[:])), | ||||
| 		mtu:  1500, | ||||
| 	device := &NativeTUN{ | ||||
| 		name:   string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]), | ||||
| 		f:      os.NewFile(uintptr(fd), string(ifName.name[:])), | ||||
| 		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
 | ||||
| 
 | ||||
| 	err = device.setMTU(DefaultMTU) | ||||
|  | @ -123,23 +178,13 @@ func CreateTUN(name string) (ifce TUNDevice, err error) { | |||
| 	return device, err | ||||
| } | ||||
| 
 | ||||
| // 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 { | ||||
| 	name string | ||||
| 	f    io.ReadWriteCloser | ||||
| 	mtu  int | ||||
| var _ io.ReadWriteCloser = (*NativeTUN)(nil) | ||||
| 
 | ||||
| 	rMu  sync.Mutex | ||||
| 	rBuf []byte | ||||
| 
 | ||||
| 	wMu  sync.Mutex | ||||
| 	wBuf []byte | ||||
| func (t *NativeTUN) Events() chan TUNEvent { | ||||
| 	return t.events | ||||
| } | ||||
| 
 | ||||
| var _ io.ReadWriteCloser = (*tunReadCloser)(nil) | ||||
| 
 | ||||
| func (t *tunReadCloser) Read(to []byte) (int, error) { | ||||
| func (t *NativeTUN) Read(to []byte) (int, error) { | ||||
| 	t.rMu.Lock() | ||||
| 	defer t.rMu.Unlock() | ||||
| 
 | ||||
|  | @ -153,7 +198,7 @@ func (t *tunReadCloser) Read(to []byte) (int, error) { | |||
| 	return n - 4, err | ||||
| } | ||||
| 
 | ||||
| func (t *tunReadCloser) Write(from []byte) (int, error) { | ||||
| func (t *NativeTUN) Write(from []byte) (int, error) { | ||||
| 
 | ||||
| 	if len(from) == 0 { | ||||
| 		return 0, unix.EIO | ||||
|  | @ -184,7 +229,7 @@ func (t *tunReadCloser) Write(from []byte) (int, error) { | |||
| 	return n - 4, err | ||||
| } | ||||
| 
 | ||||
| func (t *tunReadCloser) Close() error { | ||||
| func (t *NativeTUN) Close() error { | ||||
| 
 | ||||
| 	// lock to make sure no read/write is in process.
 | ||||
| 
 | ||||
|  | @ -197,11 +242,11 @@ func (t *tunReadCloser) Close() error { | |||
| 	return t.f.Close() | ||||
| } | ||||
| 
 | ||||
| func (t *tunReadCloser) Name() string { | ||||
| func (t *NativeTUN) Name() string { | ||||
| 	return t.name | ||||
| } | ||||
| 
 | ||||
| func (t *tunReadCloser) setMTU(n int) error { | ||||
| func (t *NativeTUN) setMTU(n int) error { | ||||
| 
 | ||||
| 	// open datagram socket
 | ||||
| 
 | ||||
|  | @ -238,7 +283,7 @@ func (t *tunReadCloser) setMTU(n int) error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (t *tunReadCloser) MTU() (int, error) { | ||||
| func (t *NativeTUN) MTU() (int, error) { | ||||
| 
 | ||||
| 	// open datagram socket
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,11 +2,22 @@ package main | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"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 { | ||||
| 	listener net.Listener // unix socket listener
 | ||||
| 	connNew  chan net.Conn | ||||
|  | @ -35,9 +46,20 @@ func (l *UAPIListener) Addr() net.Addr { | |||
| 
 | ||||
| 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
 | ||||
| 
 | ||||
| 	socketPath := fmt.Sprintf("/var/run/wireguard/%s.sock", name) | ||||
| 	socketPath := path.Join( | ||||
| 		socketDirectory, | ||||
| 		fmt.Sprintf(socketName, name), | ||||
| 	) | ||||
| 
 | ||||
| 	listener, err := net.Listen("unix", socketPath) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  |  | |||
|  | @ -18,12 +18,6 @@ const ( | |||
| 	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 { | ||||
| 	listener  net.Listener // unix socket listener
 | ||||
| 	connNew   chan net.Conn | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue