Hello,

I've been very intrigued by WinTUN, and the option of a small, simple TUN driver, especially one with good golang bindings offers a lot of opportunity to build interesting things on Windows.

I've been building a minimal program based on the go libraries, my goal being to just write a simple ICMP endpoint to be able to ping, as a way to learn the WinTUN code and libraries. Unfortunately, I've run into an issue that I'm unable to actually read from the tun device, my code always getting errors like open \\.\Global\WINTUN32768: Access is denied.

In a nutshell, my code does the following (error checking and some other ancillary code is omitted, please see this gist for the complete code):

func main() {
    // These two functions are taken from wireguard windows, added just to make sure that
    // this code is running from the same privilege level as the WireGuard windows code
    checkForAdminGroup()
    checkForWow64()
    // Create a tun. This works, with the small patch to tun_windows.go which I submitted earlier
    t, err := tun.CreateTun("My Test Tun")
    nt := t.(*tun.NativeTun)
    // Get the interface and set IPs, etc
    iface, err := winipccfg.InterfaceFromLUID(nt.LUID())
    iface.SetAddresses("172.16.16.1/24")// Omitting all the mangly code to create an IPNet
    // Listen for Reads
    wg := &sync.WaitGroup{}
    wg.Add(1)
    go func() {
        defer wg.Done()
        for {
            bt := make([]byte, 15000) // Lots of packets
            read, err := nt.Read(bt, 0) // Offset of 0 for now, just trying to read
            if err != nil {
                fmt.Printf("%#v\n", err)
                return
            }
            fmt.Printf("Read %d bytes\n", read)
        }
    }()
    wg.Wait()
}

I've tried this using two different versions of the WinTUN driver, one where I just created a simple installer using the v0.1 MSM file on WinTun.net, and the other by installing WireGuard v0.0.8 from the main website. In both cases, CreateTun and interface calls work, and I'm able to see the network adapter added to Windows. However, in both cases, the call to Read fails. Ultimately, after drilling down, the failing call is in tun_windows.go in func (tun *NativeTun) openTUN, and the offending line is tun.tunFileRead, err = os.OpenFile(name, os.O_RDONLY, 0).

To test out my code, and see if I am missing some key component, I compiled and ran golang.zx2c4.com/wireguard/main_windows.go, which exhibits the exact same behavior as my program, ending with an error like ERROR: (MyTunTest) 2019/05/21 18:14:17 Failed to read packet from TUN device: open \\.\Global\WINTUN32769: Access is denied.

At this point I was convinced that it might be some factor about my system which was preventing this from working, but much to my surprise when I downloaded and ran the current v0.0.8 release version of the WireGuard client, it worked just fine, and I was able to connect to and route traffic through a WireGuard server.

I then considered that there was something special about opening the tun device from a service specifically, as opposed to an elevated user space process (although I cannot figure out a reason why this should be so). I whipped up a very quick windows service in C# to only tries to open the already created WinTUN device (literally, just var tunRead = File.Open(TUN_NAME, FileMode.Open, FileAccess.Read);, plus all the usual service boiler plate). I installed this service with the LocalSystem permission and when starting, it similarly gets an access denied error.

Clearly, the WireGuard windows client is executing some command which puts the tun into an ready to open state or changes the privileges in some key way, but I have been unable to find this key command or function. Any help on a minimum viable program to successfully call Read on a WinTUN object is most appreciated.

All the best,

~ Christopher