Reimplemented bind_rtmgrp in pure Go
Getting rid of the Cgo dependency for listing on netlink. Ported original patch from "syscall" to "golang.org/x/sys/unix". Signed-off-by: Dominik Süß <dominik.suess@outlook.at> Co-Authored-By: Mathias Hall-Andersen <mathias@hall-andersen.dk>
This commit is contained in:
		
							parent
							
								
									ff8f3a412e
								
							
						
					
					
						commit
						fa37039c3b
					
				
					 1 changed files with 30 additions and 40 deletions
				
			
		
							
								
								
									
										70
									
								
								tun_linux.go
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								tun_linux.go
									
									
									
									
									
								
							|  | @ -16,38 +16,9 @@ import ( | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // #include <string.h>
 |  | ||||||
| // #include <unistd.h>
 |  | ||||||
| // #include <net/if.h>
 |  | ||||||
| // #include <netinet/in.h>
 |  | ||||||
| // #include <linux/netlink.h>
 |  | ||||||
| // #include <linux/rtnetlink.h>
 |  | ||||||
| //
 |  | ||||||
| // /* Creates a netlink socket
 |  | ||||||
| //  * listening to the RTMGRP_LINK multicast group
 |  | ||||||
| //  */
 |  | ||||||
| //
 |  | ||||||
| // int bind_rtmgrp() {
 |  | ||||||
| //   int nl_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 |  | ||||||
| //   if (nl_sock < 0)
 |  | ||||||
| //     return -1;
 |  | ||||||
| //
 |  | ||||||
| //	 struct sockaddr_nl addr;
 |  | ||||||
| //   memset ((void *) &addr, 0, sizeof (addr));
 |  | ||||||
| //   addr.nl_family = AF_NETLINK;
 |  | ||||||
| //   addr.nl_pid = getpid ();
 |  | ||||||
| //   addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
 |  | ||||||
| //
 |  | ||||||
| //   if (bind(nl_sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
 |  | ||||||
| //     return -1;
 |  | ||||||
| //
 |  | ||||||
| //   return nl_sock;
 |  | ||||||
| // }
 |  | ||||||
| import "C" |  | ||||||
| 
 |  | ||||||
| const ( | const ( | ||||||
| 	CloneDevicePath = "/dev/net/tun" | 	cloneDevicePath = "/dev/net/tun" | ||||||
| 	IFReqSize       = unix.IFNAMSIZ + 64 | 	ifReqSize       = unix.IFNAMSIZ + 64 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type NativeTun struct { | type NativeTun struct { | ||||||
|  | @ -58,6 +29,26 @@ type NativeTun struct { | ||||||
| 	events chan TUNEvent // device related events
 | 	events chan TUNEvent // device related events
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func toRTMGRP(sc uint) uint { | ||||||
|  | 	return 1 << (sc - 1) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (tun *NativeTun) bindRTMGRP() (int, error) { | ||||||
|  | 	groups := toRTMGRP(unix.RTNLGRP_LINK) | ||||||
|  | 	groups |= toRTMGRP(unix.RTNLGRP_IPV4_IFADDR) | ||||||
|  | 	groups |= toRTMGRP(unix.RTNLGRP_IPV6_IFADDR) | ||||||
|  | 	sock, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, unix.NETLINK_ROUTE) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	saddr := &unix.SockaddrNetlink{ | ||||||
|  | 		Family: unix.AF_NETLINK, | ||||||
|  | 		Pid:    uint32(os.Getpid()), | ||||||
|  | 		Groups: uint32(groups), | ||||||
|  | 	} | ||||||
|  | 	return sock, unix.Bind(sock, saddr) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (tun *NativeTun) File() *os.File { | func (tun *NativeTun) File() *os.File { | ||||||
| 	return tun.fd | 	return tun.fd | ||||||
| } | } | ||||||
|  | @ -81,9 +72,8 @@ func (tun *NativeTun) RoutineHackListener() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (tun *NativeTun) RoutineNetlinkListener() { | func (tun *NativeTun) RoutineNetlinkListener() { | ||||||
| 
 | 	sock, err := tun.bindRTMGRP() | ||||||
| 	sock := int(C.bind_rtmgrp()) | 	if err != nil { | ||||||
| 	if sock < 0 { |  | ||||||
| 		tun.errors <- errors.New("Failed to create netlink event listener") | 		tun.errors <- errors.New("Failed to create netlink event listener") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | @ -159,7 +149,7 @@ func getIFIndex(name string) (int32, error) { | ||||||
| 
 | 
 | ||||||
| 	defer unix.Close(fd) | 	defer unix.Close(fd) | ||||||
| 
 | 
 | ||||||
| 	var ifr [IFReqSize]byte | 	var ifr [ifReqSize]byte | ||||||
| 	copy(ifr[:], name) | 	copy(ifr[:], name) | ||||||
| 	_, _, errno := unix.Syscall( | 	_, _, errno := unix.Syscall( | ||||||
| 		unix.SYS_IOCTL, | 		unix.SYS_IOCTL, | ||||||
|  | @ -194,7 +184,7 @@ func (tun *NativeTun) setMTU(n int) error { | ||||||
| 
 | 
 | ||||||
| 	// do ioctl call
 | 	// do ioctl call
 | ||||||
| 
 | 
 | ||||||
| 	var ifr [IFReqSize]byte | 	var ifr [ifReqSize]byte | ||||||
| 	copy(ifr[:], tun.name) | 	copy(ifr[:], tun.name) | ||||||
| 	binary.LittleEndian.PutUint32(ifr[16:20], uint32(n)) | 	binary.LittleEndian.PutUint32(ifr[16:20], uint32(n)) | ||||||
| 	_, _, errno := unix.Syscall( | 	_, _, errno := unix.Syscall( | ||||||
|  | @ -229,7 +219,7 @@ func (tun *NativeTun) MTU() (int, error) { | ||||||
| 
 | 
 | ||||||
| 	// do ioctl call
 | 	// do ioctl call
 | ||||||
| 
 | 
 | ||||||
| 	var ifr [IFReqSize]byte | 	var ifr [ifReqSize]byte | ||||||
| 	copy(ifr[:], tun.name) | 	copy(ifr[:], tun.name) | ||||||
| 	_, _, errno := unix.Syscall( | 	_, _, errno := unix.Syscall( | ||||||
| 		unix.SYS_IOCTL, | 		unix.SYS_IOCTL, | ||||||
|  | @ -324,15 +314,15 @@ func CreateTUN(name string) (TUNDevice, error) { | ||||||
| 
 | 
 | ||||||
| 	// open clone device
 | 	// open clone device
 | ||||||
| 
 | 
 | ||||||
| 	fd, err := os.OpenFile(CloneDevicePath, os.O_RDWR, 0) | 	fd, err := os.OpenFile(cloneDevicePath, os.O_RDWR, 0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// create new device
 | 	// create new device
 | ||||||
| 
 | 
 | ||||||
| 	var ifr [IFReqSize]byte | 	var ifr [ifReqSize]byte | ||||||
| 	var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI
 | 	var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack)
 | ||||||
| 	nameBytes := []byte(name) | 	nameBytes := []byte(name) | ||||||
| 	if len(nameBytes) >= unix.IFNAMSIZ { | 	if len(nameBytes) >= unix.IFNAMSIZ { | ||||||
| 		return nil, errors.New("Interface name too long") | 		return nil, errors.New("Interface name too long") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue