Skip to content

Instantly share code, notes, and snippets.

@jwriteclub
Created May 21, 2019 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwriteclub/4f0fa081cb4eb39620702d7f7e212afd to your computer and use it in GitHub Desktop.
Save jwriteclub/4f0fa081cb4eb39620702d7f7e212afd to your computer and use it in GitHub Desktop.
Example code attempting to use WinTUN.
package main
import (
"fmt"
"golang.org/x/sys/windows"
"golang.zx2c4.com/winipcfg"
"golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/windows/services"
"net"
"os"
"sync"
"syscall"
"time"
"unsafe"
)
func main() {
checkForAdminGroup()
checkForWow64()
t, err := tun.CreateTUN("My WinTUN Test")
if err != nil {
fmt.Printf("Unable to create tunnel interface: %s", err.Error())
os.Exit(1)
}
nt := t.(*tun.NativeTun)
time.Sleep(time.Second * 2) // The interface sometimes isn't found if this is called too quickly after creating the Tun
// TODO: Find a better way of searching for the interface than just sleeping. Retry loop?
// Get the interface
iface, err := winipcfg.InterfaceFromLUID(nt.LUID())
if err != nil {
fmt.Printf("Unable to get interface: %s\n", err.Error())
os.Exit(1)
}
// Add an IP Address (172.16.16.1/24) and a default route to 172.16.16.0/24 through 172.16.16.1
network := &net.IPNet{IP: net.IPv4(0xAC, 0x10, 0x10, 0x01), Mask: net.IPv4Mask(0xFF, 0xFF, 0xFF, 0x00)}
fmt.Printf("Setting address %s\n", network.String())
err = iface.SetAddresses([]*net.IPNet{network})
if err != nil {
fmt.Printf("Unable to set an address on %s: %s\n", iface.AdapterName, err.Error())
os.Exit(1)
}
fmt.Printf("Adding route\n")
err = iface.AddRoute(&winipcfg.RouteData{Destination: net.IPNet{IP: net.IPv4(0xAC, 0x10, 0x10, 0x00), Mask: net.IPv4Mask(0xFF, 0xFF, 0xFF, 0x00)}, NextHop: net.IPv4(0xAC, 0x10, 0x10, 0x01), Metric: 1})
if err != nil {
fmt.Printf("Unable to add route on %s: %s\n", iface.AdapterName, err.Error())
os.Exit(1)
}
// Display the routes, just for giggles
rts, err := iface.GetRoutes(windows.AF_INET)
if err != nil {
fmt.Printf("Unable to load existing routes: %s\n", err.Error())
os.Exit(1)
} else {
for i := range rts {
fmt.Printf(" > Route: %#v\n", rts[i])
}
}
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
fmt.Printf("Starting read loop\n")
defer fmt.Printf("Closing read loop\n")
defer wg.Done()
for {
bt := make([]byte, 15000)
read, err := nt.Read(bt, 0)
if err != nil {
fmt.Printf("read error: %s\n", err.Error())
os.Exit(1)
}
fmt.Printf("Read %d bytes\n", read)
}
}()
wg.Wait()
}
func checkForAdminGroup() {
// This is not a security check, but rather a user-confusion one.
processToken, err := windows.OpenCurrentProcessToken()
if err != nil {
panic(fmt.Sprintf("Unable to open current process token: ", err))
}
defer processToken.Close()
if !services.TokenIsMemberOfBuiltInAdministrator(processToken) {
panic(fmt.Sprintf("Process may only be used by users who are a member of the Builtin Administrators group."))
} else {
fmt.Printf("Process appears to be a member of the Builtin Administrators group\n")
}
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procIsWow64Process = modkernel32.NewProc("IsWow64Process")
)
func checkForWow64() {
var b bool
p, _ := windows.GetCurrentProcess()
err := isWow64Process(p, &b)
if err != nil {
panic(fmt.Sprintf("Unable to determine whether the process is running under WOW64: ", err))
}
if b {
panic(fmt.Sprintf("You must use the 64-bit version of process on this computer."))
} else {
fmt.Printf("You appear to be running a 64-bit version of Windows")
}
}
func isWow64Process(handle windows.Handle, isWow64 *bool) (err error) {
r1, _, e1 := syscall.Syscall(procIsWow64Process.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(isWow64)), 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
)
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment