From 92261b770fdf745b6437a4f24482d19a480a00eb Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Fri, 27 Apr 2018 02:23:48 +0200
Subject: [PATCH] Fix error handling and cleanup of netlink listener

---
 tun_linux.go | 51 +++++++++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/tun_linux.go b/tun_linux.go
index 1abc86f..0672b5e 100644
--- a/tun_linux.go
+++ b/tun_linux.go
@@ -36,31 +36,15 @@ type NativeTun struct {
 	closingWriter *os.File
 }
 
-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 {
 	return tun.fd
 }
 
 func (tun *NativeTun) RoutineHackListener() {
+	// TODO: This function never actually exits in response to anything,
+	// a go routine that goes forever. We'll want to fix that if this is
+	// to ever be used as any sort of library.
+
 	/* This is needed for the detection to work across network namespaces
 	 * If you are reading this and know a better method, please get in touch.
 	 */
@@ -78,12 +62,35 @@ func (tun *NativeTun) RoutineHackListener() {
 	}
 }
 
+func toRTMGRP(sc uint) uint {
+	return 1 << (sc - 1)
+}
+
 func (tun *NativeTun) RoutineNetlinkListener() {
-	sock, err := tun.bindRTMGRP()
+
+	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 {
-		tun.errors <- errors.New("Failed to create netlink event listener")
+		tun.errors <- errors.New("Failed to create netlink event listener socket")
 		return
 	}
+	defer unix.Close(sock)
+	saddr := &unix.SockaddrNetlink{
+		Family: unix.AF_NETLINK,
+		Pid:    uint32(os.Getpid()),
+		Groups: uint32(groups),
+	}
+	err = unix.Bind(sock, saddr)
+	if err != nil {
+		tun.errors <- errors.New("Failed to bind netlink event listener socket")
+		return
+	}
+
+	// TODO: This function never actually exits in response to anything,
+	// a go routine that goes forever. We'll want to fix that if this is
+	// to ever be used as any sort of library.
 
 	for msg := make([]byte, 1<<16); ; {