diff options
author | Simon Rozman <simon@rozman.si> | 2020-07-22 09:15:49 +0200 |
---|---|---|
committer | Simon Rozman <simon@rozman.si> | 2020-11-07 12:46:35 +0100 |
commit | 3e08b8aee0f6ae038f6316ca1bb84e5214db318f (patch) | |
tree | 34681cb00b6b22bded95e0df6ed271de18983646 /tun | |
parent | 5ca1218a5c16fb9b5e99b61c0b5758f66087e2e4 (diff) |
wintun: migrate to wintun.dll API
Rather than having every application using Wintun driver reinvent the
wheel, the Wintun device/adapter/interface management has been moved
from wireguard-go to wintun.dll deployed with Wintun itself.
Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'tun')
25 files changed, 169 insertions, 3711 deletions
diff --git a/tun/tun_windows.go b/tun/tun_windows.go index 5a52c56..684d6f0 100644 --- a/tun/tun_windows.go +++ b/tun/tun_windows.go @@ -33,7 +33,7 @@ type rateJuggler struct { } type NativeTun struct { - wt *wintun.Interface + wt *wintun.Adapter handle windows.Handle close bool events chan Event @@ -44,7 +44,15 @@ type NativeTun struct { writeLock sync.Mutex } -const WintunPool = wintun.Pool("WireGuard") +var WintunPool *wintun.Pool + +func init() { + var err error + WintunPool, err = wintun.MakePool("WireGuard") + if err != nil { + panic(fmt.Errorf("Failed to make pool: %v", err)) + } +} //go:linkname procyield runtime.procyield func procyield(cycles uint32) @@ -66,18 +74,18 @@ func CreateTUN(ifname string, mtu int) (Device, error) { // func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID, mtu int) (Device, error) { var err error - var wt *wintun.Interface + var wt *wintun.Adapter // Does an interface with this name already exist? - wt, err = WintunPool.GetInterface(ifname) + wt, err = WintunPool.OpenAdapter(ifname) if err == nil { // If so, we delete it, in case it has weird residual configuration. - _, err = wt.DeleteInterface() + _, err = wt.Delete(true) if err != nil { return nil, fmt.Errorf("Error deleting already existing interface: %v", err) } } - wt, _, err = WintunPool.CreateInterface(ifname, requestedGUID) + wt, _, err = WintunPool.CreateAdapter(ifname, requestedGUID) if err != nil { return nil, fmt.Errorf("Error creating interface: %v", err) } @@ -132,7 +140,7 @@ func (tun *NativeTun) Close() error { tun.rings.Close() var err error if tun.wt != nil { - _, err = tun.wt.DeleteInterface() + _, err = tun.wt.Delete(false) } close(tun.events) return err @@ -254,9 +262,9 @@ func (tun *NativeTun) LUID() uint64 { return tun.wt.LUID() } -// Version returns the version of the Wintun driver and NDIS system currently loaded. -func (tun *NativeTun) Version() (driverVersion string, ndisVersion string, err error) { - return tun.wt.Version() +// RunningVersion returns the running version of the Wintun driver. +func (tun *NativeTun) RunningVersion() (version uint32, err error) { + return wintun.RunningVersion() } func (rate *rateJuggler) update(packetLen uint64) { diff --git a/tun/wintun/iphlpapi/conversion_windows.go b/tun/wintun/iphlpapi/conversion_windows.go deleted file mode 100644 index d2db8a3..0000000 --- a/tun/wintun/iphlpapi/conversion_windows.go +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package iphlpapi - -import "golang.org/x/sys/windows" - -//sys convertInterfaceLUIDToGUID(interfaceLUID *uint64, interfaceGUID *windows.GUID) (ret error) = iphlpapi.ConvertInterfaceLuidToGuid -//sys convertInterfaceAliasToLUID(interfaceAlias *uint16, interfaceLUID *uint64) (ret error) = iphlpapi.ConvertInterfaceAliasToLuid - -func InterfaceGUIDFromAlias(alias string) (*windows.GUID, error) { - var luid uint64 - var guid windows.GUID - err := convertInterfaceAliasToLUID(windows.StringToUTF16Ptr(alias), &luid) - if err != nil { - return nil, err - } - err = convertInterfaceLUIDToGUID(&luid, &guid) - if err != nil { - return nil, err - } - return &guid, nil -} diff --git a/tun/wintun/iphlpapi/mksyscall.go b/tun/wintun/iphlpapi/mksyscall.go deleted file mode 100644 index 8ffc0d4..0000000 --- a/tun/wintun/iphlpapi/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package iphlpapi - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go conversion_windows.go diff --git a/tun/wintun/iphlpapi/zsyscall_windows.go b/tun/wintun/iphlpapi/zsyscall_windows.go deleted file mode 100644 index dc14294..0000000 --- a/tun/wintun/iphlpapi/zsyscall_windows.go +++ /dev/null @@ -1,60 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package iphlpapi - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -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 -} - -var ( - modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll") - - procConvertInterfaceLuidToGuid = modiphlpapi.NewProc("ConvertInterfaceLuidToGuid") - procConvertInterfaceAliasToLuid = modiphlpapi.NewProc("ConvertInterfaceAliasToLuid") -) - -func convertInterfaceLUIDToGUID(interfaceLUID *uint64, interfaceGUID *windows.GUID) (ret error) { - r0, _, _ := syscall.Syscall(procConvertInterfaceLuidToGuid.Addr(), 2, uintptr(unsafe.Pointer(interfaceLUID)), uintptr(unsafe.Pointer(interfaceGUID)), 0) - if r0 != 0 { - ret = syscall.Errno(r0) - } - return -} - -func convertInterfaceAliasToLUID(interfaceAlias *uint16, interfaceLUID *uint64) (ret error) { - r0, _, _ := syscall.Syscall(procConvertInterfaceAliasToLuid.Addr(), 2, uintptr(unsafe.Pointer(interfaceAlias)), uintptr(unsafe.Pointer(interfaceLUID)), 0) - if r0 != 0 { - ret = syscall.Errno(r0) - } - return -} diff --git a/tun/wintun/namespace_windows.go b/tun/wintun/namespace_windows.go deleted file mode 100644 index 302ad45..0000000 --- a/tun/wintun/namespace_windows.go +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package wintun - -import ( - "encoding/hex" - "errors" - "fmt" - "sync" - "unsafe" - - "golang.org/x/crypto/blake2s" - "golang.org/x/sys/windows" - "golang.org/x/text/unicode/norm" - - "golang.zx2c4.com/wireguard/tun/wintun/namespaceapi" -) - -var ( - wintunObjectSecurityAttributes *windows.SecurityAttributes - hasInitializedNamespace bool - initializingNamespace sync.Mutex -) - -func initializeNamespace() error { - initializingNamespace.Lock() - defer initializingNamespace.Unlock() - if hasInitializedNamespace { - return nil - } - sd, err := windows.SecurityDescriptorFromString("O:SYD:P(A;;GA;;;SY)") - if err != nil { - return fmt.Errorf("SddlToSecurityDescriptor failed: %v", err) - } - wintunObjectSecurityAttributes = &windows.SecurityAttributes{ - Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})), - SecurityDescriptor: sd, - } - sid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) - if err != nil { - return fmt.Errorf("CreateWellKnownSid(LOCAL_SYSTEM) failed: %v", err) - } - - boundary, err := namespaceapi.CreateBoundaryDescriptor("Wintun") - if err != nil { - return fmt.Errorf("CreateBoundaryDescriptor failed: %v", err) - } - err = boundary.AddSid(sid) - if err != nil { - return fmt.Errorf("AddSIDToBoundaryDescriptor failed: %v", err) - } - for { - _, err = namespaceapi.CreatePrivateNamespace(wintunObjectSecurityAttributes, boundary, "Wintun") - if err == windows.ERROR_ALREADY_EXISTS { - _, err = namespaceapi.OpenPrivateNamespace(boundary, "Wintun") - if err == windows.ERROR_PATH_NOT_FOUND { - continue - } - if err != nil { - return fmt.Errorf("OpenPrivateNamespace failed: %v", err) - } - } - if err != nil { - return fmt.Errorf("CreatePrivateNamespace failed: %v", err) - } - break - } - hasInitializedNamespace = true - return nil -} - -func (pool Pool) takeNameMutex() (windows.Handle, error) { - err := initializeNamespace() - if err != nil { - return 0, err - } - - const mutexLabel = "WireGuard Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com" - b2, _ := blake2s.New256(nil) - b2.Write([]byte(mutexLabel)) - b2.Write(norm.NFC.Bytes([]byte(string(pool)))) - mutexName := `Wintun\Wintun-Name-Mutex-` + hex.EncodeToString(b2.Sum(nil)) - mutex, err := windows.CreateMutex(wintunObjectSecurityAttributes, false, windows.StringToUTF16Ptr(mutexName)) - if err != nil { - err = fmt.Errorf("Error creating name mutex: %v", err) - return 0, err - } - event, err := windows.WaitForSingleObject(mutex, windows.INFINITE) - if err != nil { - windows.CloseHandle(mutex) - return 0, fmt.Errorf("Error waiting on name mutex: %v", err) - } - if event != windows.WAIT_OBJECT_0 && event != windows.WAIT_ABANDONED { - windows.CloseHandle(mutex) - return 0, errors.New("Error with event trigger of name mutex") - } - return mutex, nil -} diff --git a/tun/wintun/namespaceapi/mksyscall.go b/tun/wintun/namespaceapi/mksyscall.go deleted file mode 100644 index 8ea3085..0000000 --- a/tun/wintun/namespaceapi/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package namespaceapi - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go namespaceapi_windows.go diff --git a/tun/wintun/namespaceapi/namespaceapi_windows.go b/tun/wintun/namespaceapi/namespaceapi_windows.go deleted file mode 100644 index e71077c..0000000 --- a/tun/wintun/namespaceapi/namespaceapi_windows.go +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package namespaceapi - -import "golang.org/x/sys/windows" - -//sys createBoundaryDescriptor(name *uint16, flags uint32) (handle windows.Handle, err error) = kernel32.CreateBoundaryDescriptorW -//sys deleteBoundaryDescriptor(boundaryDescriptor windows.Handle) = kernel32.DeleteBoundaryDescriptor -//sys addSIDToBoundaryDescriptor(boundaryDescriptor *windows.Handle, requiredSid *windows.SID) (err error) = kernel32.AddSIDToBoundaryDescriptor -//sys createPrivateNamespace(privateNamespaceAttributes *windows.SecurityAttributes, boundaryDescriptor windows.Handle, aliasPrefix *uint16) (handle windows.Handle, err error) = kernel32.CreatePrivateNamespaceW -//sys openPrivateNamespace(boundaryDescriptor windows.Handle, aliasPrefix *uint16) (handle windows.Handle, err error) = kernel32.OpenPrivateNamespaceW -//sys closePrivateNamespace(handle windows.Handle, flags uint32) (err error) = kernel32.ClosePrivateNamespace - -// BoundaryDescriptor represents a boundary that defines how the objects in the namespace are to be isolated. -type BoundaryDescriptor windows.Handle - -// CreateBoundaryDescriptor creates a boundary descriptor. -func CreateBoundaryDescriptor(name string) (BoundaryDescriptor, error) { - name16, err := windows.UTF16PtrFromString(name) - if err != nil { - return 0, err - } - handle, err := createBoundaryDescriptor(name16, 0) - if err != nil { - return 0, err - } - return BoundaryDescriptor(handle), nil -} - -// Delete deletes the specified boundary descriptor. -func (bd BoundaryDescriptor) Delete() { - deleteBoundaryDescriptor(windows.Handle(bd)) -} - -// AddSid adds a security identifier (SID) to the specified boundary descriptor. -func (bd *BoundaryDescriptor) AddSid(requiredSid *windows.SID) error { - return addSIDToBoundaryDescriptor((*windows.Handle)(bd), requiredSid) -} - -// PrivateNamespace represents a private namespace. -type PrivateNamespace windows.Handle - -// CreatePrivateNamespace creates a private namespace. -func CreatePrivateNamespace(privateNamespaceAttributes *windows.SecurityAttributes, boundaryDescriptor BoundaryDescriptor, aliasPrefix string) (PrivateNamespace, error) { - aliasPrefix16, err := windows.UTF16PtrFromString(aliasPrefix) - if err != nil { - return 0, err - } - handle, err := createPrivateNamespace(privateNamespaceAttributes, windows.Handle(boundaryDescriptor), aliasPrefix16) - if err != nil { - return 0, err - } - return PrivateNamespace(handle), nil -} - -// OpenPrivateNamespace opens a private namespace. -func OpenPrivateNamespace(boundaryDescriptor BoundaryDescriptor, aliasPrefix string) (PrivateNamespace, error) { - aliasPrefix16, err := windows.UTF16PtrFromString(aliasPrefix) - if err != nil { - return 0, err - } - handle, err := openPrivateNamespace(windows.Handle(boundaryDescriptor), aliasPrefix16) - if err != nil { - return 0, err - } - return PrivateNamespace(handle), nil -} - -// ClosePrivateNamespaceFlags describes flags that are used by PrivateNamespace's Close() method. -type ClosePrivateNamespaceFlags uint32 - -const ( - // PrivateNamespaceFlagDestroy makes the close to destroy the namespace. - PrivateNamespaceFlagDestroy = ClosePrivateNamespaceFlags(0x1) -) - -// Close closes an open namespace handle. -func (pns PrivateNamespace) Close(flags ClosePrivateNamespaceFlags) error { - return closePrivateNamespace(windows.Handle(pns), uint32(flags)) -} diff --git a/tun/wintun/namespaceapi/zsyscall_windows.go b/tun/wintun/namespaceapi/zsyscall_windows.go deleted file mode 100644 index 508c223..0000000 --- a/tun/wintun/namespaceapi/zsyscall_windows.go +++ /dev/null @@ -1,116 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package namespaceapi - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -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 -} - -var ( - modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - - procCreateBoundaryDescriptorW = modkernel32.NewProc("CreateBoundaryDescriptorW") - procDeleteBoundaryDescriptor = modkernel32.NewProc("DeleteBoundaryDescriptor") - procAddSIDToBoundaryDescriptor = modkernel32.NewProc("AddSIDToBoundaryDescriptor") - procCreatePrivateNamespaceW = modkernel32.NewProc("CreatePrivateNamespaceW") - procOpenPrivateNamespaceW = modkernel32.NewProc("OpenPrivateNamespaceW") - procClosePrivateNamespace = modkernel32.NewProc("ClosePrivateNamespace") -) - -func createBoundaryDescriptor(name *uint16, flags uint32) (handle windows.Handle, err error) { - r0, _, e1 := syscall.Syscall(procCreateBoundaryDescriptorW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(flags), 0) - handle = windows.Handle(r0) - if handle == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func deleteBoundaryDescriptor(boundaryDescriptor windows.Handle) { - syscall.Syscall(procDeleteBoundaryDescriptor.Addr(), 1, uintptr(boundaryDescriptor), 0, 0) - return -} - -func addSIDToBoundaryDescriptor(boundaryDescriptor *windows.Handle, requiredSid *windows.SID) (err error) { - r1, _, e1 := syscall.Syscall(procAddSIDToBoundaryDescriptor.Addr(), 2, uintptr(unsafe.Pointer(boundaryDescriptor)), uintptr(unsafe.Pointer(requiredSid)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func createPrivateNamespace(privateNamespaceAttributes *windows.SecurityAttributes, boundaryDescriptor windows.Handle, aliasPrefix *uint16) (handle windows.Handle, err error) { - r0, _, e1 := syscall.Syscall(procCreatePrivateNamespaceW.Addr(), 3, uintptr(unsafe.Pointer(privateNamespaceAttributes)), uintptr(boundaryDescriptor), uintptr(unsafe.Pointer(aliasPrefix))) - handle = windows.Handle(r0) - if handle == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func openPrivateNamespace(boundaryDescriptor windows.Handle, aliasPrefix *uint16) (handle windows.Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenPrivateNamespaceW.Addr(), 2, uintptr(boundaryDescriptor), uintptr(unsafe.Pointer(aliasPrefix)), 0) - handle = windows.Handle(r0) - if handle == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func closePrivateNamespace(handle windows.Handle, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procClosePrivateNamespace.Addr(), 2, uintptr(handle), uintptr(flags), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} diff --git a/tun/wintun/nci/mksyscall.go b/tun/wintun/nci/mksyscall.go deleted file mode 100644 index 129e015..0000000 --- a/tun/wintun/nci/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package nci - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go nci_windows.go diff --git a/tun/wintun/nci/nci_windows.go b/tun/wintun/nci/nci_windows.go deleted file mode 100644 index dc9733c..0000000 --- a/tun/wintun/nci/nci_windows.go +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package nci - -import "golang.org/x/sys/windows" - -//sys nciSetConnectionName(guid *windows.GUID, newName *uint16) (ret error) = nci.NciSetConnectionName -//sys nciGetConnectionName(guid *windows.GUID, destName *uint16, inDestNameBytes uint32, outDestNameBytes *uint32) (ret error) = nci.NciGetConnectionName - -func SetConnectionName(guid *windows.GUID, newName string) error { - newName16, err := windows.UTF16PtrFromString(newName) - if err != nil { - return err - } - return nciSetConnectionName(guid, newName16) -} - -func ConnectionName(guid *windows.GUID) (string, error) { - var name [0x400]uint16 - err := nciGetConnectionName(guid, &name[0], uint32(len(name)*2), nil) - if err != nil { - return "", err - } - return windows.UTF16ToString(name[:]), nil -} diff --git a/tun/wintun/nci/zsyscall_windows.go b/tun/wintun/nci/zsyscall_windows.go deleted file mode 100644 index 2a7b79e..0000000 --- a/tun/wintun/nci/zsyscall_windows.go +++ /dev/null @@ -1,60 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package nci - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -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 -} - -var ( - modnci = windows.NewLazySystemDLL("nci.dll") - - procNciSetConnectionName = modnci.NewProc("NciSetConnectionName") - procNciGetConnectionName = modnci.NewProc("NciGetConnectionName") -) - -func nciSetConnectionName(guid *windows.GUID, newName *uint16) (ret error) { - r0, _, _ := syscall.Syscall(procNciSetConnectionName.Addr(), 2, uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(newName)), 0) - if r0 != 0 { - ret = syscall.Errno(r0) - } - return -} - -func nciGetConnectionName(guid *windows.GUID, destName *uint16, inDestNameBytes uint32, outDestNameBytes *uint32) (ret error) { - r0, _, _ := syscall.Syscall6(procNciGetConnectionName.Addr(), 4, uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(destName)), uintptr(inDestNameBytes), uintptr(unsafe.Pointer(outDestNameBytes)), 0, 0) - if r0 != 0 { - ret = syscall.Errno(r0) - } - return -} diff --git a/tun/wintun/registry/mksyscall.go b/tun/wintun/registry/mksyscall.go deleted file mode 100644 index 3e9ff1f..0000000 --- a/tun/wintun/registry/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package registry - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zregistry_windows.go registry_windows.go diff --git a/tun/wintun/registry/registry_windows.go b/tun/wintun/registry/registry_windows.go deleted file mode 100644 index 70419a5..0000000 --- a/tun/wintun/registry/registry_windows.go +++ /dev/null @@ -1,272 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package registry - -import ( - "errors" - "fmt" - "runtime" - "strings" - "time" - "unsafe" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -const ( - // REG_NOTIFY_CHANGE_NAME notifies the caller if a subkey is added or deleted. - REG_NOTIFY_CHANGE_NAME uint32 = 0x00000001 - - // REG_NOTIFY_CHANGE_ATTRIBUTES notifies the caller of changes to the attributes of the key, such as the security descriptor information. - REG_NOTIFY_CHANGE_ATTRIBUTES uint32 = 0x00000002 - - // REG_NOTIFY_CHANGE_LAST_SET notifies the caller of changes to a value of the key. This can include adding or deleting a value, or changing an existing value. - REG_NOTIFY_CHANGE_LAST_SET uint32 = 0x00000004 - - // REG_NOTIFY_CHANGE_SECURITY notifies the caller of changes to the security descriptor of the key. - REG_NOTIFY_CHANGE_SECURITY uint32 = 0x00000008 - - // REG_NOTIFY_THREAD_AGNOSTIC indicates that the lifetime of the registration must not be tied to the lifetime of the thread issuing the RegNotifyChangeKeyValue call. Note: This flag value is only supported in Windows 8 and later. - REG_NOTIFY_THREAD_AGNOSTIC uint32 = 0x10000000 -) - -//sys regNotifyChangeKeyValue(key windows.Handle, watchSubtree bool, notifyFilter uint32, event windows.Handle, asynchronous bool) (regerrno error) = advapi32.RegNotifyChangeKeyValue - -func OpenKeyWait(k registry.Key, path string, access uint32, timeout time.Duration) (registry.Key, error) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - deadline := time.Now().Add(timeout) - pathSpl := strings.Split(path, "\\") - for i := 0; ; i++ { - keyName := pathSpl[i] - isLast := i+1 == len(pathSpl) - - event, err := windows.CreateEvent(nil, 0, 0, nil) - if err != nil { - return 0, fmt.Errorf("Error creating event: %v", err) - } - defer windows.CloseHandle(event) - - var key registry.Key - for { - err = regNotifyChangeKeyValue(windows.Handle(k), false, REG_NOTIFY_CHANGE_NAME, windows.Handle(event), true) - if err != nil { - return 0, fmt.Errorf("Setting up change notification on registry key failed: %v", err) - } - - var accessFlags uint32 - if isLast { - accessFlags = access - } else { - accessFlags = registry.NOTIFY - } - key, err = registry.OpenKey(k, keyName, accessFlags) - if err == windows.ERROR_FILE_NOT_FOUND || err == windows.ERROR_PATH_NOT_FOUND { - timeout := time.Until(deadline) / time.Millisecond - if timeout < 0 { - timeout = 0 - } - s, err := windows.WaitForSingleObject(event, uint32(timeout)) - if err != nil { - return 0, fmt.Errorf("Unable to wait on registry key: %v", err) - } - if s == uint32(windows.WAIT_TIMEOUT) { // windows.WAIT_TIMEOUT status const is misclassified as error in golang.org/x/sys/windows - return 0, errors.New("Timeout waiting for registry key") - } - } else if err != nil { - return 0, fmt.Errorf("Error opening registry key %v: %v", path, err) - } else { - if isLast { - return key, nil - } - defer key.Close() - break - } - } - - k = key - } -} - -func WaitForKey(k registry.Key, path string, timeout time.Duration) error { - key, err := OpenKeyWait(k, path, registry.NOTIFY, timeout) - if err != nil { - return err - } - key.Close() - return nil -} - -// -// getValue is more or less the same as windows/registry's getValue. -// -func getValue(k registry.Key, name string, buf []byte) (value []byte, valueType uint32, err error) { - var name16 *uint16 - name16, err = windows.UTF16PtrFromString(name) - if err != nil { - return - } - n := uint32(len(buf)) - for { - err = windows.RegQueryValueEx(windows.Handle(k), name16, nil, &valueType, (*byte)(unsafe.Pointer(&buf[0])), &n) - if err == nil { - value = buf[:n] - return - } - if err != windows.ERROR_MORE_DATA { - return - } - if n <= uint32(len(buf)) { - return - } - buf = make([]byte, n) - } -} - -// -// getValueRetry function reads any value from registry. It waits for -// the registry value to become available or returns error on timeout. -// -// Key must be opened with at least QUERY_VALUE|NOTIFY access. -// -func getValueRetry(key registry.Key, name string, buf []byte, timeout time.Duration) ([]byte, uint32, error) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - event, err := windows.CreateEvent(nil, 0, 0, nil) - if err != nil { - return nil, 0, fmt.Errorf("Error creating event: %v", err) - } - defer windows.CloseHandle(event) - - deadline := time.Now().Add(timeout) - for { - err := regNotifyChangeKeyValue(windows.Handle(key), false, REG_NOTIFY_CHANGE_LAST_SET, windows.Handle(event), true) - if err != nil { - return nil, 0, fmt.Errorf("Setting up change notification on registry value failed: %v", err) - } - - buf, valueType, err := getValue(key, name, buf) - if err == windows.ERROR_FILE_NOT_FOUND || err == windows.ERROR_PATH_NOT_FOUND { - timeout := time.Until(deadline) / time.Millisecond - if timeout < 0 { - timeout = 0 - } - s, err := windows.WaitForSingleObject(event, uint32(timeout)) - if err != nil { - return nil, 0, fmt.Errorf("Unable to wait on registry value: %v", err) - } - if s == uint32(windows.WAIT_TIMEOUT) { // windows.WAIT_TIMEOUT status const is misclassified as error in golang.org/x/sys/windows - return nil, 0, errors.New("Timeout waiting for registry value") - } - } else if err != nil { - return nil, 0, fmt.Errorf("Error reading registry value %v: %v", name, err) - } else { - return buf, valueType, nil - } - } -} - -func toString(buf []byte, valueType uint32, err error) (string, error) { - if err != nil { - return "", err - } - - var value string - switch valueType { - case registry.SZ, registry.EXPAND_SZ, registry.MULTI_SZ: - if len(buf) == 0 { - return "", nil - } - value = windows.UTF16PtrToString((*uint16)(unsafe.Pointer(&buf[0]))) - - default: - return "", registry.ErrUnexpectedType - } - - if valueType != registry.EXPAND_SZ { - // Value does not require expansion. - return value, nil - } - - valueExp, err := registry.ExpandString(value) - if err != nil { - // Expanding failed: return original sting value. - return value, nil - } - - // Return expanded value. - return valueExp, nil -} - -func toInteger(buf []byte, valueType uint32, err error) (uint64, error) { - if err != nil { - return 0, err - } - - switch valueType { - case registry.DWORD: - if len(buf) != 4 { - return 0, errors.New("DWORD value is not 4 bytes long") - } - var val uint32 - copy((*[4]byte)(unsafe.Pointer(&val))[:], buf) - return uint64(val), nil - - case registry.QWORD: - if len(buf) != 8 { - return 0, errors.New("QWORD value is not 8 bytes long") - } - var val uint64 - copy((*[8]byte)(unsafe.Pointer(&val))[:], buf) - return val, nil - - default: - return 0, registry.ErrUnexpectedType - } -} - -// -// GetStringValueWait function reads a string value from registry. It waits -// for the registry value to become available or returns error on timeout. -// -// Key must be opened with at least QUERY_VALUE|NOTIFY access. -// -// If the value type is REG_EXPAND_SZ the environment variables are expanded. -// Should expanding fail, original string value and nil error are returned. -// -// If the value type is REG_MULTI_SZ only the first string is returned. -// -func GetStringValueWait(key registry.Key, name string, timeout time.Duration) (string, error) { - return toString(getValueRetry(key, name, make([]byte, 256), timeout)) -} - -// -// GetStringValue function reads a string value from registry. -// -// Key must be opened with at least QUERY_VALUE access. -// -// If the value type is REG_EXPAND_SZ the environment variables are expanded. -// Should expanding fail, original string value and nil error are returned. -// -// If the value type is REG_MULTI_SZ only the first string is returned. -// -func GetStringValue(key registry.Key, name string) (string, error) { - return toString(getValue(key, name, make([]byte, 256))) -} - -// -// GetIntegerValueWait function reads a DWORD32 or QWORD value from registry. -// It waits for the registry value to become available or returns error on -// timeout. -// -// Key must be opened with at least QUERY_VALUE|NOTIFY access. -// -func GetIntegerValueWait(key registry.Key, name string, timeout time.Duration) (uint64, error) { - return toInteger(getValueRetry(key, name, make([]byte, 8), timeout)) -} diff --git a/tun/wintun/registry/registry_windows_test.go b/tun/wintun/registry/registry_windows_test.go deleted file mode 100644 index 2479b3d..0000000 --- a/tun/wintun/registry/registry_windows_test.go +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package registry - -import ( - "testing" - "time" - - "golang.org/x/sys/windows/registry" -) - -const keyRoot = registry.CURRENT_USER -const pathRoot = "Software\\WireGuardRegistryTest" -const path = pathRoot + "\\foobar" -const pathFake = pathRoot + "\\raboof" - -func Test_WaitForKey(t *testing.T) { - registry.DeleteKey(keyRoot, path) - registry.DeleteKey(keyRoot, pathRoot) - go func() { - time.Sleep(time.Second * 1) - key, _, err := registry.CreateKey(keyRoot, pathFake, registry.QUERY_VALUE) - if err != nil { - t.Errorf("Error creating registry key: %v", err) - } - key.Close() - registry.DeleteKey(keyRoot, pathFake) - - key, _, err = registry.CreateKey(keyRoot, path, registry.QUERY_VALUE) - if err != nil { - t.Errorf("Error creating registry key: %v", err) - } - key.Close() - }() - err := WaitForKey(keyRoot, path, time.Second*2) - if err != nil { - t.Errorf("Error waiting for registry key: %v", err) - } - registry.DeleteKey(keyRoot, path) - registry.DeleteKey(keyRoot, pathRoot) - - err = WaitForKey(keyRoot, path, time.Second*1) - if err == nil { - t.Error("Registry key notification expected to timeout but it succeeded.") - } -} - -func Test_GetValueWait(t *testing.T) { - registry.DeleteKey(keyRoot, path) - registry.DeleteKey(keyRoot, pathRoot) - go func() { - time.Sleep(time.Second * 1) - key, _, err := registry.CreateKey(keyRoot, path, registry.SET_VALUE) - if err != nil { - t.Errorf("Error creating registry key: %v", err) - } - time.Sleep(time.Second * 1) - key.SetStringValue("name1", "eulav") - key.SetExpandStringValue("name2", "value") - time.Sleep(time.Second * 1) - key.SetDWordValue("name3", ^uint32(123)) - key.SetDWordValue("name4", 123) - key.Close() - }() - - key, err := OpenKeyWait(keyRoot, path, registry.QUERY_VALUE|registry.NOTIFY, time.Second*2) - if err != nil { - t.Errorf("Error waiting for registry key: %v", err) - } - - valueStr, err := GetStringValueWait(key, "name2", time.Second*2) - if err != nil { - t.Errorf("Error waiting for registry value: %v", err) - } - if valueStr != "value" { - t.Errorf("Wrong value read: %v", valueStr) - } - - _, err = GetStringValueWait(key, "nonexisting", time.Second*1) - if err == nil { - t.Error("Registry value notification expected to timeout but it succeeded.") - } - - valueInt, err := GetIntegerValueWait(key, "name4", time.Second*2) - if err != nil { - t.Errorf("Error waiting for registry value: %v", err) - } - if valueInt != 123 { - t.Errorf("Wrong value read: %v", valueInt) - } - - _, err = GetIntegerValueWait(key, "nonexisting", time.Second*1) - if err == nil { - t.Error("Registry value notification expected to timeout but it succeeded.") - } - - key.Close() - registry.DeleteKey(keyRoot, path) - registry.DeleteKey(keyRoot, pathRoot) -} diff --git a/tun/wintun/registry/zregistry_windows.go b/tun/wintun/registry/zregistry_windows.go deleted file mode 100644 index f7ac33b..0000000 --- a/tun/wintun/registry/zregistry_windows.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package registry - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -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 -} - -var ( - modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") - - procRegNotifyChangeKeyValue = modadvapi32.NewProc("RegNotifyChangeKeyValue") -) - -func regNotifyChangeKeyValue(key windows.Handle, watchSubtree bool, notifyFilter uint32, event windows.Handle, asynchronous bool) (regerrno error) { - var _p0 uint32 - if watchSubtree { - _p0 = 1 - } else { - _p0 = 0 - } - var _p1 uint32 - if asynchronous { - _p1 = 1 - } else { - _p1 = 0 - } - r0, _, _ := syscall.Syscall6(procRegNotifyChangeKeyValue.Addr(), 5, uintptr(key), uintptr(_p0), uintptr(notifyFilter), uintptr(event), uintptr(_p1), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} diff --git a/tun/wintun/ring_windows.go b/tun/wintun/ring_windows.go index 4d2fab6..ed460fb 100644 --- a/tun/wintun/ring_windows.go +++ b/tun/wintun/ring_windows.go @@ -103,8 +103,8 @@ func (descriptor *RingDescriptor) Close() { } } -func (wintun *Interface) Register(descriptor *RingDescriptor) (windows.Handle, error) { - handle, err := wintun.handle() +func (wintun *Adapter) Register(descriptor *RingDescriptor) (windows.Handle, error) { + handle, err := wintun.OpenAdapterDeviceObject() if err != nil { return 0, err } diff --git a/tun/wintun/setupapi/mksyscall.go b/tun/wintun/setupapi/mksyscall.go deleted file mode 100644 index 234851c..0000000 --- a/tun/wintun/setupapi/mksyscall.go +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsetupapi_windows.go setupapi_windows.go diff --git a/tun/wintun/setupapi/setupapi_windows.go b/tun/wintun/setupapi/setupapi_windows.go deleted file mode 100644 index a804dd8..0000000 --- a/tun/wintun/setupapi/setupapi_windows.go +++ /dev/null @@ -1,506 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -import ( - "encoding/binary" - "fmt" - "runtime" - "unsafe" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -//sys setupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiCreateDeviceInfoListExW - -// SetupDiCreateDeviceInfoListEx function creates an empty device information set on a remote or a local computer and optionally associates the set with a device setup class. -func SetupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName string) (deviceInfoSet DevInfo, err error) { - var machineNameUTF16 *uint16 - if machineName != "" { - machineNameUTF16, err = windows.UTF16PtrFromString(machineName) - if err != nil { - return - } - } - return setupDiCreateDeviceInfoListEx(classGUID, hwndParent, machineNameUTF16, 0) -} - -//sys setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) = setupapi.SetupDiGetDeviceInfoListDetailW - -// SetupDiGetDeviceInfoListDetail function retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name. -func SetupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo) (deviceInfoSetDetailData *DevInfoListDetailData, err error) { - data := &DevInfoListDetailData{} - data.size = sizeofDevInfoListDetailData - - return data, setupDiGetDeviceInfoListDetail(deviceInfoSet, data) -} - -// DeviceInfoListDetail method retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name. -func (deviceInfoSet DevInfo) DeviceInfoListDetail() (*DevInfoListDetailData, error) { - return SetupDiGetDeviceInfoListDetail(deviceInfoSet) -} - -//sys setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *windows.GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCreateDeviceInfoW - -// SetupDiCreateDeviceInfo function creates a new device information element and adds it as a new member to the specified device information set. -func SetupDiCreateDeviceInfo(deviceInfoSet DevInfo, deviceName string, classGUID *windows.GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (deviceInfoData *DevInfoData, err error) { - deviceNameUTF16, err := windows.UTF16PtrFromString(deviceName) - if err != nil { - return - } - - var deviceDescriptionUTF16 *uint16 - if deviceDescription != "" { - deviceDescriptionUTF16, err = windows.UTF16PtrFromString(deviceDescription) - if err != nil { - return - } - } - - data := &DevInfoData{} - data.size = uint32(unsafe.Sizeof(*data)) - - return data, setupDiCreateDeviceInfo(deviceInfoSet, deviceNameUTF16, classGUID, deviceDescriptionUTF16, hwndParent, creationFlags, data) -} - -// CreateDeviceInfo method creates a new device information element and adds it as a new member to the specified device information set. -func (deviceInfoSet DevInfo) CreateDeviceInfo(deviceName string, classGUID *windows.GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (*DevInfoData, error) { - return SetupDiCreateDeviceInfo(deviceInfoSet, deviceName, classGUID, deviceDescription, hwndParent, creationFlags) -} - -//sys setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiEnumDeviceInfo - -// SetupDiEnumDeviceInfo function returns a DevInfoData structure that specifies a device information element in a device information set. -func SetupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex int) (*DevInfoData, error) { - data := &DevInfoData{} - data.size = uint32(unsafe.Sizeof(*data)) - - return data, setupDiEnumDeviceInfo(deviceInfoSet, uint32(memberIndex), data) -} - -// EnumDeviceInfo method returns a DevInfoData structure that specifies a device information element in a device information set. -func (deviceInfoSet DevInfo) EnumDeviceInfo(memberIndex int) (*DevInfoData, error) { - return SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex) -} - -// SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory. -//sys SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiDestroyDeviceInfoList - -// Close method deletes a device information set and frees all associated memory. -func (deviceInfoSet DevInfo) Close() error { - return SetupDiDestroyDeviceInfoList(deviceInfoSet) -} - -//sys SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiBuildDriverInfoList - -// BuildDriverInfoList method builds a list of drivers that is associated with a specific device or with the global class driver list for a device information set. -func (deviceInfoSet DevInfo) BuildDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error { - return SetupDiBuildDriverInfoList(deviceInfoSet, deviceInfoData, driverType) -} - -//sys SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiCancelDriverInfoSearch - -// CancelDriverInfoSearch method cancels a driver list search that is currently in progress in a different thread. -func (deviceInfoSet DevInfo) CancelDriverInfoSearch() error { - return SetupDiCancelDriverInfoSearch(deviceInfoSet) -} - -//sys setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiEnumDriverInfoW - -// SetupDiEnumDriverInfo function enumerates the members of a driver list. -func SetupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) { - data := &DrvInfoData{} - data.size = uint32(unsafe.Sizeof(*data)) - - return data, setupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, uint32(memberIndex), data) -} - -// EnumDriverInfo method enumerates the members of a driver list. -func (deviceInfoSet DevInfo) EnumDriverInfo(deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) { - return SetupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, memberIndex) -} - -//sys setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiGetSelectedDriverW - -// SetupDiGetSelectedDriver function retrieves the selected driver for a device information set or a particular device information element. -func SetupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DrvInfoData, error) { - data := &DrvInfoData{} - data.size = uint32(unsafe.Sizeof(*data)) - - return data, setupDiGetSelectedDriver(deviceInfoSet, deviceInfoData, data) -} - -// SelectedDriver method retrieves the selected driver for a device information set or a particular device information element. -func (deviceInfoSet DevInfo) SelectedDriver(deviceInfoData *DevInfoData) (*DrvInfoData, error) { - return SetupDiGetSelectedDriver(deviceInfoSet, deviceInfoData) -} - -//sys SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiSetSelectedDriverW - -// SetSelectedDriver method sets, or resets, the selected driver for a device information element or the selected class driver for a device information set. -func (deviceInfoSet DevInfo) SetSelectedDriver(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) error { - return SetupDiSetSelectedDriver(deviceInfoSet, deviceInfoData, driverInfoData) -} - -//sys setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDriverInfoDetailW - -// SetupDiGetDriverInfoDetail function retrieves driver information detail for a device information set or a particular device information element in the device information set. -func SetupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) { - reqSize := uint32(2048) - for { - buf := make([]byte, reqSize) - data := (*DrvInfoDetailData)(unsafe.Pointer(&buf[0])) - data.size = sizeofDrvInfoDetailData - err := setupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData, data, uint32(len(buf)), &reqSize) - if err == windows.ERROR_INSUFFICIENT_BUFFER { - continue - } - if err != nil { - return nil, err - } - data.size = reqSize - return data, nil - } -} - -// DriverInfoDetail method retrieves driver information detail for a device information set or a particular device information element in the device information set. -func (deviceInfoSet DevInfo) DriverInfoDetail(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) { - return SetupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData) -} - -//sys SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiDestroyDriverInfoList - -// DestroyDriverInfoList method deletes a driver list. -func (deviceInfoSet DevInfo) DestroyDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error { - return SetupDiDestroyDriverInfoList(deviceInfoSet, deviceInfoData, driverType) -} - -//sys setupDiGetClassDevsEx(classGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiGetClassDevsExW - -// SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer. -func SetupDiGetClassDevsEx(classGUID *windows.GUID, enumerator string, hwndParent uintptr, flags DIGCF, deviceInfoSet DevInfo, machineName string) (handle DevInfo, err error) { - var enumeratorUTF16 *uint16 - if enumerator != "" { - enumeratorUTF16, err = windows.UTF16PtrFromString(enumerator) - if err != nil { - return - } - } - var machineNameUTF16 *uint16 - if machineName != "" { - machineNameUTF16, err = windows.UTF16PtrFromString(machineName) - if err != nil { - return - } - } - return setupDiGetClassDevsEx(classGUID, enumeratorUTF16, hwndParent, flags, deviceInfoSet, machineNameUTF16, 0) -} - -// SetupDiCallClassInstaller function calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code). -//sys SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCallClassInstaller - -// CallClassInstaller member calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code). -func (deviceInfoSet DevInfo) CallClassInstaller(installFunction DI_FUNCTION, deviceInfoData *DevInfoData) error { - return SetupDiCallClassInstaller(installFunction, deviceInfoSet, deviceInfoData) -} - -//sys setupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key windows.Handle, err error) [failretval==windows.InvalidHandle] = setupapi.SetupDiOpenDevRegKey - -// SetupDiOpenDevRegKey function opens a registry key for device-specific configuration information. -func SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, scope DICS_FLAG, hwProfile uint32, keyType DIREG, samDesired uint32) (registry.Key, error) { - handle, err := setupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, scope, hwProfile, keyType, samDesired) - return registry.Key(handle), err -} - -// OpenDevRegKey method opens a registry key for device-specific configuration information. -func (deviceInfoSet DevInfo) OpenDevRegKey(DeviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (registry.Key, error) { - return SetupDiOpenDevRegKey(deviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired) -} - -//sys setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceRegistryPropertyW - -// SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play device property. -func SetupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP) (value interface{}, err error) { - reqSize := uint32(256) - for { - var dataType uint32 - buf := make([]byte, reqSize) - err = setupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, &buf[0], uint32(len(buf)), &reqSize) - if err == windows.ERROR_INSUFFICIENT_BUFFER { - continue - } - if err != nil { - return - } - return getRegistryValue(buf[:reqSize], dataType) - } -} - -func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { - switch dataType { - case windows.REG_SZ: - ret := windows.UTF16ToString(bufToUTF16(buf)) - runtime.KeepAlive(buf) - return ret, nil - case windows.REG_EXPAND_SZ: - ret, err := registry.ExpandString(windows.UTF16ToString(bufToUTF16(buf))) - runtime.KeepAlive(buf) - return ret, err - case windows.REG_BINARY: - return buf, nil - case windows.REG_DWORD_LITTLE_ENDIAN: - return binary.LittleEndian.Uint32(buf), nil - case windows.REG_DWORD_BIG_ENDIAN: - return binary.BigEndian.Uint32(buf), nil - case windows.REG_MULTI_SZ: - bufW := bufToUTF16(buf) - a := []string{} - for i := 0; i < len(bufW); { - j := i + wcslen(bufW[i:]) - if i < j { - a = append(a, windows.UTF16ToString(bufW[i:j])) - } - i = j + 1 - } - runtime.KeepAlive(buf) - return a, nil - case windows.REG_QWORD_LITTLE_ENDIAN: - return binary.LittleEndian.Uint64(buf), nil - default: - return nil, fmt.Errorf("Unsupported registry value type: %v", dataType) - } -} - -// bufToUTF16 function reinterprets []byte buffer as []uint16 -func bufToUTF16(buf []byte) []uint16 { - sl := struct { - addr *uint16 - len int - cap int - }{(*uint16)(unsafe.Pointer(&buf[0])), len(buf) / 2, cap(buf) / 2} - return *(*[]uint16)(unsafe.Pointer(&sl)) -} - -// utf16ToBuf function reinterprets []uint16 as []byte -func utf16ToBuf(buf []uint16) []byte { - sl := struct { - addr *byte - len int - cap int - }{(*byte)(unsafe.Pointer(&buf[0])), len(buf) * 2, cap(buf) * 2} - return *(*[]byte)(unsafe.Pointer(&sl)) -} - -func wcslen(str []uint16) int { - for i := 0; i < len(str); i++ { - if str[i] == 0 { - return i - } - } - return len(str) -} - -// DeviceRegistryProperty method retrieves a specified Plug and Play device property. -func (deviceInfoSet DevInfo) DeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP) (interface{}, error) { - return SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property) -} - -//sys setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) = setupapi.SetupDiSetDeviceRegistryPropertyW - -// SetupDiSetDeviceRegistryProperty function sets a Plug and Play device property for a device. -func SetupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error { - return setupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &propertyBuffers[0], uint32(len(propertyBuffers))) -} - -// SetDeviceRegistryProperty function sets a Plug and Play device property for a device. -func (deviceInfoSet DevInfo) SetDeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error { - return SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyBuffers) -} - -// SetDeviceRegistryPropertyString method sets a Plug and Play device property string for a device. -func (deviceInfoSet DevInfo) SetDeviceRegistryPropertyString(deviceInfoData *DevInfoData, property SPDRP, str string) error { - str16, err := windows.UTF16FromString(str) - if err != nil { - return err - } - err = SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, utf16ToBuf(append(str16, 0))) - runtime.KeepAlive(str16) - return err -} - -//sys setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiGetDeviceInstallParamsW - -// SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element. -func SetupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DevInstallParams, error) { - params := &DevInstallParams{} - params.size = uint32(unsafe.Sizeof(*params)) - - return params, setupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, params) -} - -// DeviceInstallParams method retrieves device installation parameters for a device information set or a particular device information element. -func (deviceInfoSet DevInfo) DeviceInstallParams(deviceInfoData *DevInfoData) (*DevInstallParams, error) { - return SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData) -} - -//sys setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceInstanceIdW - -// SetupDiGetDeviceInstanceId function retrieves the instance ID of the device. -func SetupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (string, error) { - reqSize := uint32(1024) - for { - buf := make([]uint16, reqSize) - err := setupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, &buf[0], uint32(len(buf)), &reqSize) - if err == windows.ERROR_INSUFFICIENT_BUFFER { - continue - } - if err != nil { - return "", err - } - return windows.UTF16ToString(buf), nil - } -} - -// DeviceInstanceID method retrieves the instance ID of the device. -func (deviceInfoSet DevInfo) DeviceInstanceID(deviceInfoData *DevInfoData) (string, error) { - return SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData) -} - -// SetupDiGetClassInstallParams function retrieves class installation parameters for a device information set or a particular device information element. -//sys SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetClassInstallParamsW - -// ClassInstallParams method retrieves class installation parameters for a device information set or a particular device information element. -func (deviceInfoSet DevInfo) ClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) error { - return SetupDiGetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize, requiredSize) -} - -//sys SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiSetDeviceInstallParamsW - -// SetDeviceInstallParams member sets device installation parameters for a device information set or a particular device information element. -func (deviceInfoSet DevInfo) SetDeviceInstallParams(deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) error { - return SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams) -} - -// SetupDiSetClassInstallParams function sets or clears class install parameters for a device information set or a particular device information element. -//sys SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) = setupapi.SetupDiSetClassInstallParamsW - -// SetClassInstallParams method sets or clears class install parameters for a device information set or a particular device information element. -func (deviceInfoSet DevInfo) SetClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) error { - return SetupDiSetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize) -} - -//sys setupDiClassNameFromGuidEx(classGUID *windows.GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassNameFromGuidExW - -// SetupDiClassNameFromGuidEx function retrieves the class name associated with a class GUID. The class can be installed on a local or remote computer. -func SetupDiClassNameFromGuidEx(classGUID *windows.GUID, machineName string) (className string, err error) { - var classNameUTF16 [MAX_CLASS_NAME_LEN]uint16 - - var machineNameUTF16 *uint16 - if machineName != "" { - machineNameUTF16, err = windows.UTF16PtrFromString(machineName) - if err != nil { - return - } - } - - err = setupDiClassNameFromGuidEx(classGUID, &classNameUTF16[0], MAX_CLASS_NAME_LEN, nil, machineNameUTF16, 0) - if err != nil { - return - } - - className = windows.UTF16ToString(classNameUTF16[:]) - return -} - -//sys setupDiClassGuidsFromNameEx(className *uint16, classGuidList *windows.GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassGuidsFromNameExW - -// SetupDiClassGuidsFromNameEx function retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote computer. -func SetupDiClassGuidsFromNameEx(className string, machineName string) ([]windows.GUID, error) { - classNameUTF16, err := windows.UTF16PtrFromString(className) - if err != nil { - return nil, err - } - - var machineNameUTF16 *uint16 - if machineName != "" { - machineNameUTF16, err = windows.UTF16PtrFromString(machineName) - if err != nil { - return nil, err - } - } - - reqSize := uint32(4) - for { - buf := make([]windows.GUID, reqSize) - err = setupDiClassGuidsFromNameEx(classNameUTF16, &buf[0], uint32(len(buf)), &reqSize, machineNameUTF16, 0) - if err == windows.ERROR_INSUFFICIENT_BUFFER { - continue - } - if err != nil { - return nil, err - } - return buf[:reqSize], nil - } -} - -//sys setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiGetSelectedDevice - -// SetupDiGetSelectedDevice function retrieves the selected device information element in a device information set. -func SetupDiGetSelectedDevice(deviceInfoSet DevInfo) (*DevInfoData, error) { - data := &DevInfoData{} - data.size = uint32(unsafe.Sizeof(*data)) - - return data, setupDiGetSelectedDevice(deviceInfoSet, data) -} - -// SelectedDevice method retrieves the selected device information element in a device information set. -func (deviceInfoSet DevInfo) SelectedDevice() (*DevInfoData, error) { - return SetupDiGetSelectedDevice(deviceInfoSet) -} - -// SetupDiSetSelectedDevice function sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard. -//sys SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiSetSelectedDevice - -// SetSelectedDevice method sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard. -func (deviceInfoSet DevInfo) SetSelectedDevice(deviceInfoData *DevInfoData) error { - return SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData) -} - -//sys cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *windows.GUID, deviceID *uint16, flags uint32) (ret uint32) = CfgMgr32.CM_Get_Device_Interface_List_SizeW -//sys cm_Get_Device_Interface_List(interfaceClass *windows.GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret uint32) = CfgMgr32.CM_Get_Device_Interface_ListW - -func CM_Get_Device_Interface_List(deviceID string, interfaceClass *windows.GUID, flags uint32) ([]string, error) { - deviceID16, err := windows.UTF16PtrFromString(deviceID) - if err != nil { - return nil, err - } - var buf []uint16 - var buflen uint32 - for { - if ret := cm_Get_Device_Interface_List_Size(&buflen, interfaceClass, deviceID16, flags); ret != CR_SUCCESS { - return nil, fmt.Errorf("CfgMgr error: 0x%x", ret) - } - buf = make([]uint16, buflen) - if ret := cm_Get_Device_Interface_List(interfaceClass, deviceID16, &buf[0], buflen, flags); ret == CR_SUCCESS { - break - } else if ret != CR_BUFFER_SMALL { - return nil, fmt.Errorf("CfgMgr error: 0x%x", ret) - } - } - var interfaces []string - for i := 0; i < len(buf); { - j := i + wcslen(buf[i:]) - if i < j { - interfaces = append(interfaces, windows.UTF16ToString(buf[i:j])) - } - i = j + 1 - } - if interfaces == nil { - return nil, fmt.Errorf("no interfaces found") - } - return interfaces, nil -} diff --git a/tun/wintun/setupapi/setupapi_windows_test.go b/tun/wintun/setupapi/setupapi_windows_test.go deleted file mode 100644 index b0afbc7..0000000 --- a/tun/wintun/setupapi/setupapi_windows_test.go +++ /dev/null @@ -1,488 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -import ( - "runtime" - "strings" - "testing" - - "golang.org/x/sys/windows" -) - -var deviceClassNetGUID = windows.GUID{Data1: 0x4d36e972, Data2: 0xe325, Data3: 0x11ce, Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}} -var computerName string - -func init() { - computerName, _ = windows.ComputerName() -} - -func TestSetupDiCreateDeviceInfoListEx(t *testing.T) { - devInfoList, err := SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, "") - if err != nil { - t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error()) - } else { - devInfoList.Close() - } - - devInfoList, err = SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, computerName) - if err != nil { - t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error()) - } else { - devInfoList.Close() - } - - devInfoList, err = SetupDiCreateDeviceInfoListEx(nil, 0, "") - if err != nil { - t.Errorf("Error calling SetupDiCreateDeviceInfoListEx(nil): %s", err.Error()) - } else { - devInfoList.Close() - } -} - -func TestSetupDiGetDeviceInfoListDetail(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - data, err := devInfoList.DeviceInfoListDetail() - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceInfoListDetail: %s", err.Error()) - } else { - if data.ClassGUID != deviceClassNetGUID { - t.Error("SetupDiGetDeviceInfoListDetail returned different class GUID") - } - - if data.RemoteMachineHandle != windows.Handle(0) { - t.Error("SetupDiGetDeviceInfoListDetail returned non-NULL remote machine handle") - } - - if data.RemoteMachineName() != "" { - t.Error("SetupDiGetDeviceInfoListDetail returned non-NULL remote machine name") - } - } - - devInfoList, err = SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), computerName) - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - data, err = devInfoList.DeviceInfoListDetail() - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceInfoListDetail: %s", err.Error()) - } else { - if data.ClassGUID != deviceClassNetGUID { - t.Error("SetupDiGetDeviceInfoListDetail returned different class GUID") - } - - if data.RemoteMachineHandle == windows.Handle(0) { - t.Error("SetupDiGetDeviceInfoListDetail returned NULL remote machine handle") - } - - if data.RemoteMachineName() != computerName { - t.Error("SetupDiGetDeviceInfoListDetail returned different remote machine name") - } - } - - data = &DevInfoListDetailData{} - data.SetRemoteMachineName("foobar") - if data.RemoteMachineName() != "foobar" { - t.Error("DevInfoListDetailData.(Get|Set)RemoteMachineName() differ") - } -} - -func TestSetupDiCreateDeviceInfo(t *testing.T) { - devInfoList, err := SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, computerName) - if err != nil { - t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error()) - } - defer devInfoList.Close() - - deviceClassNetName, err := SetupDiClassNameFromGuidEx(&deviceClassNetGUID, computerName) - if err != nil { - t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error()) - } - - devInfoData, err := devInfoList.CreateDeviceInfo(deviceClassNetName, &deviceClassNetGUID, "This is a test device", 0, DICD_GENERATE_ID) - if err != nil { - // Access denied is expected, as the SetupDiCreateDeviceInfo() require elevation to succeed. - if errWin, ok := err.(windows.Errno); !ok || errWin != windows.ERROR_ACCESS_DENIED { - t.Errorf("Error calling SetupDiCreateDeviceInfo: %s", err.Error()) - } - } else if devInfoData.ClassGUID != deviceClassNetGUID { - t.Error("SetupDiCreateDeviceInfo returned different class GUID") - } -} - -func TestSetupDiEnumDeviceInfo(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - data, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - if data.ClassGUID != deviceClassNetGUID { - t.Error("SetupDiEnumDeviceInfo returned different class GUID") - } - - _, err = devInfoList.DeviceInstanceID(data) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceInstanceId: %s", err.Error()) - } - } -} - -func TestDevInfo_BuildDriverInfoList(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - deviceData, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - const driverType SPDIT = SPDIT_COMPATDRIVER - err = devInfoList.BuildDriverInfoList(deviceData, driverType) - if err != nil { - t.Errorf("Error calling SetupDiBuildDriverInfoList: %s", err.Error()) - } - defer devInfoList.DestroyDriverInfoList(deviceData, driverType) - - var selectedDriverData *DrvInfoData - for j := 0; true; j++ { - driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, j) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - if driverData.DriverType == 0 { - continue - } - - if !driverData.IsNewer(windows.Filetime{}, 0) { - t.Error("Driver should have non-zero date and version") - } - if !driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime}, 0) { - t.Error("Driver should have non-zero date and version") - } - if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime + 1}, 0) { - t.Error("Driver should report newer version on high-date-time") - } - if !driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, 0) { - t.Error("Driver should have non-zero version") - } - if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime + 1}, 0) { - t.Error("Driver should report newer version on low-date-time") - } - if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, driverData.DriverVersion) { - t.Error("Driver should not be newer than itself") - } - if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, driverData.DriverVersion+1) { - t.Error("Driver should report newer version on version") - } - - err = devInfoList.SetSelectedDriver(deviceData, driverData) - if err != nil { - t.Errorf("Error calling SetupDiSetSelectedDriver: %s", err.Error()) - } else { - selectedDriverData = driverData - } - - driverDetailData, err := devInfoList.DriverInfoDetail(deviceData, driverData) - if err != nil { - t.Errorf("Error calling SetupDiGetDriverInfoDetail: %s", err.Error()) - } - - if driverDetailData.IsCompatible("foobar-aab6e3a4-144e-4786-88d3-6cec361e1edd") { - t.Error("Invalid HWID compatibitlity reported") - } - if !driverDetailData.IsCompatible(strings.ToUpper(driverDetailData.HardwareID())) { - t.Error("HWID compatibitlity missed") - } - a := driverDetailData.CompatIDs() - for k := range a { - if !driverDetailData.IsCompatible(strings.ToUpper(a[k])) { - t.Error("HWID compatibitlity missed") - } - } - } - - selectedDriverData2, err := devInfoList.SelectedDriver(deviceData) - if err != nil { - t.Errorf("Error calling SetupDiGetSelectedDriver: %s", err.Error()) - } else if *selectedDriverData != *selectedDriverData2 { - t.Error("SetupDiGetSelectedDriver should return driver selected with SetupDiSetSelectedDriver") - } - } - - data := &DrvInfoData{} - data.SetDescription("foobar") - if data.Description() != "foobar" { - t.Error("DrvInfoData.(Get|Set)Description() differ") - } - data.SetMfgName("foobar") - if data.MfgName() != "foobar" { - t.Error("DrvInfoData.(Get|Set)MfgName() differ") - } - data.SetProviderName("foobar") - if data.ProviderName() != "foobar" { - t.Error("DrvInfoData.(Get|Set)ProviderName() differ") - } -} - -func TestSetupDiGetClassDevsEx(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "PCI", 0, DIGCF_PRESENT, DevInfo(0), computerName) - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } else { - devInfoList.Close() - } - - devInfoList, err = SetupDiGetClassDevsEx(nil, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - if errWin, ok := err.(windows.Errno); !ok || errWin != windows.ERROR_INVALID_PARAMETER { - t.Errorf("SetupDiGetClassDevsEx(nil, ...) should fail with ERROR_INVALID_PARAMETER") - } - } else { - devInfoList.Close() - t.Errorf("SetupDiGetClassDevsEx(nil, ...) should fail") - } -} - -func TestSetupDiOpenDevRegKey(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - data, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - key, err := devInfoList.OpenDevRegKey(data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, windows.KEY_READ) - if err != nil { - t.Errorf("Error calling SetupDiOpenDevRegKey: %s", err.Error()) - } - defer key.Close() - } -} - -func TestSetupDiGetDeviceRegistryProperty(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - data, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - val, err := devInfoList.DeviceRegistryProperty(data, SPDRP_CLASS) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CLASS): %s", err.Error()) - } else if class, ok := val.(string); !ok || strings.ToLower(class) != "net" { - t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASS) should return \"Net\"") - } - - val, err = devInfoList.DeviceRegistryProperty(data, SPDRP_CLASSGUID) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID): %s", err.Error()) - } else if valStr, ok := val.(string); !ok { - t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID) should return string") - } else { - classGUID, err := windows.GUIDFromString(valStr) - if err != nil { - t.Errorf("Error parsing GUID returned by SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID): %s", err.Error()) - } else if classGUID != deviceClassNetGUID { - t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID) should return %x", deviceClassNetGUID) - } - } - - val, err = devInfoList.DeviceRegistryProperty(data, SPDRP_COMPATIBLEIDS) - if err != nil { - // Some devices have no SPDRP_COMPATIBLEIDS. - if errWin, ok := err.(windows.Errno); !ok || errWin != windows.ERROR_INVALID_DATA { - t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_COMPATIBLEIDS): %s", err.Error()) - } - } - - val, err = devInfoList.DeviceRegistryProperty(data, SPDRP_CONFIGFLAGS) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CONFIGFLAGS): %s", err.Error()) - } - - val, err = devInfoList.DeviceRegistryProperty(data, SPDRP_DEVICE_POWER_DATA) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_DEVICE_POWER_DATA): %s", err.Error()) - } - } -} - -func TestSetupDiGetDeviceInstallParams(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - data, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - _, err = devInfoList.DeviceInstallParams(data) - if err != nil { - t.Errorf("Error calling SetupDiGetDeviceInstallParams: %s", err.Error()) - } - } - - params := &DevInstallParams{} - params.SetDriverPath("foobar") - if params.DriverPath() != "foobar" { - t.Error("DevInstallParams.(Get|Set)DriverPath() differ") - } -} - -func TestSetupDiClassNameFromGuidEx(t *testing.T) { - deviceClassNetName, err := SetupDiClassNameFromGuidEx(&deviceClassNetGUID, "") - if err != nil { - t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error()) - } else if strings.ToLower(deviceClassNetName) != "net" { - t.Errorf("SetupDiClassNameFromGuidEx(%x) should return \"Net\"", deviceClassNetGUID) - } - - deviceClassNetName, err = SetupDiClassNameFromGuidEx(&deviceClassNetGUID, computerName) - if err != nil { - t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error()) - } else if strings.ToLower(deviceClassNetName) != "net" { - t.Errorf("SetupDiClassNameFromGuidEx(%x) should return \"Net\"", deviceClassNetGUID) - } - - _, err = SetupDiClassNameFromGuidEx(nil, "") - if err != nil { - if errWin, ok := err.(windows.Errno); !ok || errWin != windows.ERROR_INVALID_USER_BUFFER { - t.Errorf("SetupDiClassNameFromGuidEx(nil) should fail with ERROR_INVALID_USER_BUFFER") - } - } else { - t.Errorf("SetupDiClassNameFromGuidEx(nil) should fail") - } -} - -func TestSetupDiClassGuidsFromNameEx(t *testing.T) { - ClassGUIDs, err := SetupDiClassGuidsFromNameEx("Net", "") - if err != nil { - t.Errorf("Error calling SetupDiClassGuidsFromNameEx: %s", err.Error()) - } else { - found := false - for i := range ClassGUIDs { - if ClassGUIDs[i] == deviceClassNetGUID { - found = true - break - } - } - if !found { - t.Errorf("SetupDiClassGuidsFromNameEx(\"Net\") should return %x", deviceClassNetGUID) - } - } - - ClassGUIDs, err = SetupDiClassGuidsFromNameEx("foobar-34274a51-a6e6-45f0-80d6-c62be96dd5fe", computerName) - if err != nil { - t.Errorf("Error calling SetupDiClassGuidsFromNameEx: %s", err.Error()) - } else if len(ClassGUIDs) != 0 { - t.Errorf("SetupDiClassGuidsFromNameEx(\"foobar-34274a51-a6e6-45f0-80d6-c62be96dd5fe\") should return an empty GUID set") - } -} - -func TestSetupDiGetSelectedDevice(t *testing.T) { - devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "") - if err != nil { - t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error()) - } - defer devInfoList.Close() - - for i := 0; true; i++ { - data, err := devInfoList.EnumDeviceInfo(i) - if err != nil { - if errWin, ok := err.(windows.Errno); ok && errWin == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - err = devInfoList.SetSelectedDevice(data) - if err != nil { - t.Errorf("Error calling SetupDiSetSelectedDevice: %s", err.Error()) - } - - data2, err := devInfoList.SelectedDevice() - if err != nil { - t.Errorf("Error calling SetupDiGetSelectedDevice: %s", err.Error()) - } else if *data != *data2 { - t.Error("SetupDiGetSelectedDevice returned different data than was set by SetupDiSetSelectedDevice") - } - } - - err = devInfoList.SetSelectedDevice(nil) - if err != nil { - if errWin, ok := err.(windows.Errno); !ok || errWin != windows.ERROR_INVALID_PARAMETER { - t.Errorf("SetupDiSetSelectedDevice(nil) should fail with ERROR_INVALID_USER_BUFFER") - } - } else { - t.Errorf("SetupDiSetSelectedDevice(nil) should fail") - } -} - -func TestUTF16ToBuf(t *testing.T) { - buf := []uint16{0x0123, 0x4567, 0x89ab, 0xcdef} - buf2 := utf16ToBuf(buf) - if len(buf)*2 != len(buf2) || - cap(buf)*2 != cap(buf2) || - buf2[0] != 0x23 || buf2[1] != 0x01 || - buf2[2] != 0x67 || buf2[3] != 0x45 || - buf2[4] != 0xab || buf2[5] != 0x89 || - buf2[6] != 0xef || buf2[7] != 0xcd { - t.Errorf("SetupDiSetSelectedDevice(nil) should fail with ERROR_INVALID_USER_BUFFER") - } - runtime.KeepAlive(buf) -} diff --git a/tun/wintun/setupapi/types32_windows.go b/tun/wintun/setupapi/types32_windows.go deleted file mode 100644 index 0eaead6..0000000 --- a/tun/wintun/setupapi/types32_windows.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build 386 arm - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -const ( - sizeofDevInfoListDetailData uint32 = 550 - sizeofDrvInfoDetailData uint32 = 1570 -) diff --git a/tun/wintun/setupapi/types64_windows.go b/tun/wintun/setupapi/types64_windows.go deleted file mode 100644 index c815b8f..0000000 --- a/tun/wintun/setupapi/types64_windows.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build amd64 arm64 - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -const ( - sizeofDevInfoListDetailData uint32 = 560 - sizeofDrvInfoDetailData uint32 = 1584 -) diff --git a/tun/wintun/setupapi/types_windows.go b/tun/wintun/setupapi/types_windows.go deleted file mode 100644 index 43e3f39..0000000 --- a/tun/wintun/setupapi/types_windows.go +++ /dev/null @@ -1,568 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -import ( - "strings" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - MAX_DEVICE_ID_LEN = 200 - MAX_DEVNODE_ID_LEN = MAX_DEVICE_ID_LEN - MAX_GUID_STRING_LEN = 39 // 38 chars + terminator null - MAX_CLASS_NAME_LEN = 32 - MAX_PROFILE_LEN = 80 - MAX_CONFIG_VALUE = 9999 - MAX_INSTANCE_VALUE = 9999 - CONFIGMG_VERSION = 0x0400 -) - -// -// Define maximum string length constants -// -const ( - ANYSIZE_ARRAY = 1 - LINE_LEN = 256 // Windows 9x-compatible maximum for displayable strings coming from a device INF. - MAX_INF_STRING_LENGTH = 4096 // Actual maximum size of an INF string (including string substitutions). - MAX_INF_SECTION_NAME_LENGTH = 255 // For Windows 9x compatibility, INF section names should be constrained to 32 characters. - MAX_TITLE_LEN = 60 - MAX_INSTRUCTION_LEN = 256 - MAX_LABEL_LEN = 30 - MAX_SERVICE_NAME_LEN = 256 - MAX_SUBTITLE_LEN = 256 -) - -const ( - // SP_MAX_MACHINENAME_LENGTH defines maximum length of a machine name in the format expected by ConfigMgr32 CM_Connect_Machine (i.e., "\\\\MachineName\0"). - SP_MAX_MACHINENAME_LENGTH = windows.MAX_PATH + 3 -) - -// HSPFILEQ is type for setup file queue -type HSPFILEQ uintptr - -// DevInfo holds reference to device information set -type DevInfo windows.Handle - -// DevInfoData is a device information structure (references a device instance that is a member of a device information set) -type DevInfoData struct { - size uint32 - ClassGUID windows.GUID - DevInst uint32 // DEVINST handle - _ uintptr -} - -// DevInfoListDetailData is a structure for detailed information on a device information set (used for SetupDiGetDeviceInfoListDetail which supersedes the functionality of SetupDiGetDeviceInfoListClass). -type DevInfoListDetailData struct { - size uint32 // Warning: unsafe.Sizeof(DevInfoListDetailData) > sizeof(SP_DEVINFO_LIST_DETAIL_DATA) when GOARCH == 386 => use sizeofDevInfoListDetailData const. - ClassGUID windows.GUID - RemoteMachineHandle windows.Handle - remoteMachineName [SP_MAX_MACHINENAME_LENGTH]uint16 -} - -func (data *DevInfoListDetailData) RemoteMachineName() string { - return windows.UTF16ToString(data.remoteMachineName[:]) -} - -func (data *DevInfoListDetailData) SetRemoteMachineName(remoteMachineName string) error { - str, err := windows.UTF16FromString(remoteMachineName) - if err != nil { - return err - } - copy(data.remoteMachineName[:], str) - return nil -} - -// DI_FUNCTION is function type for device installer -type DI_FUNCTION uint32 - -const ( - DIF_SELECTDEVICE DI_FUNCTION = 0x00000001 - DIF_INSTALLDEVICE DI_FUNCTION = 0x00000002 - DIF_ASSIGNRESOURCES DI_FUNCTION = 0x00000003 - DIF_PROPERTIES DI_FUNCTION = 0x00000004 - DIF_REMOVE DI_FUNCTION = 0x00000005 - DIF_FIRSTTIMESETUP DI_FUNCTION = 0x00000006 - DIF_FOUNDDEVICE DI_FUNCTION = 0x00000007 - DIF_SELECTCLASSDRIVERS DI_FUNCTION = 0x00000008 - DIF_VALIDATECLASSDRIVERS DI_FUNCTION = 0x00000009 - DIF_INSTALLCLASSDRIVERS DI_FUNCTION = 0x0000000A - DIF_CALCDISKSPACE DI_FUNCTION = 0x0000000B - DIF_DESTROYPRIVATEDATA DI_FUNCTION = 0x0000000C - DIF_VALIDATEDRIVER DI_FUNCTION = 0x0000000D - DIF_DETECT DI_FUNCTION = 0x0000000F - DIF_INSTALLWIZARD DI_FUNCTION = 0x00000010 - DIF_DESTROYWIZARDDATA DI_FUNCTION = 0x00000011 - DIF_PROPERTYCHANGE DI_FUNCTION = 0x00000012 - DIF_ENABLECLASS DI_FUNCTION = 0x00000013 - DIF_DETECTVERIFY DI_FUNCTION = 0x00000014 - DIF_INSTALLDEVICEFILES DI_FUNCTION = 0x00000015 - DIF_UNREMOVE DI_FUNCTION = 0x00000016 - DIF_SELECTBESTCOMPATDRV DI_FUNCTION = 0x00000017 - DIF_ALLOW_INSTALL DI_FUNCTION = 0x00000018 - DIF_REGISTERDEVICE DI_FUNCTION = 0x00000019 - DIF_NEWDEVICEWIZARD_PRESELECT DI_FUNCTION = 0x0000001A - DIF_NEWDEVICEWIZARD_SELECT DI_FUNCTION = 0x0000001B - DIF_NEWDEVICEWIZARD_PREANALYZE DI_FUNCTION = 0x0000001C - DIF_NEWDEVICEWIZARD_POSTANALYZE DI_FUNCTION = 0x0000001D - DIF_NEWDEVICEWIZARD_FINISHINSTALL DI_FUNCTION = 0x0000001E - DIF_INSTALLINTERFACES DI_FUNCTION = 0x00000020 - DIF_DETECTCANCEL DI_FUNCTION = 0x00000021 - DIF_REGISTER_COINSTALLERS DI_FUNCTION = 0x00000022 - DIF_ADDPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000023 - DIF_ADDPROPERTYPAGE_BASIC DI_FUNCTION = 0x00000024 - DIF_TROUBLESHOOTER DI_FUNCTION = 0x00000026 - DIF_POWERMESSAGEWAKE DI_FUNCTION = 0x00000027 - DIF_ADDREMOTEPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000028 - DIF_UPDATEDRIVER_UI DI_FUNCTION = 0x00000029 - DIF_FINISHINSTALL_ACTION DI_FUNCTION = 0x0000002A -) - -// DevInstallParams is device installation parameters structure (associated with a particular device information element, or globally with a device information set) -type DevInstallParams struct { - size uint32 - Flags DI_FLAGS - FlagsEx DI_FLAGSEX - hwndParent uintptr - InstallMsgHandler uintptr - InstallMsgHandlerContext uintptr - FileQueue HSPFILEQ - _ uintptr - _ uint32 - driverPath [windows.MAX_PATH]uint16 -} - -func (params *DevInstallParams) DriverPath() string { - return windows.UTF16ToString(params.driverPath[:]) -} - -func (params *DevInstallParams) SetDriverPath(driverPath string) error { - str, err := windows.UTF16FromString(driverPath) - if err != nil { - return err - } - copy(params.driverPath[:], str) - return nil -} - -// DI_FLAGS is SP_DEVINSTALL_PARAMS.Flags values -type DI_FLAGS uint32 - -const ( - // Flags for choosing a device - DI_SHOWOEM DI_FLAGS = 0x00000001 // support Other... button - DI_SHOWCOMPAT DI_FLAGS = 0x00000002 // show compatibility list - DI_SHOWCLASS DI_FLAGS = 0x00000004 // show class list - DI_SHOWALL DI_FLAGS = 0x00000007 // both class & compat list shown - DI_NOVCP DI_FLAGS = 0x00000008 // don't create a new copy queue--use caller-supplied FileQueue - DI_DIDCOMPAT DI_FLAGS = 0x00000010 // Searched for compatible devices - DI_DIDCLASS DI_FLAGS = 0x00000020 // Searched for class devices - DI_AUTOASSIGNRES DI_FLAGS = 0x00000040 // No UI for resources if possible - - // Flags returned by DiInstallDevice to indicate need to reboot/restart - DI_NEEDRESTART DI_FLAGS = 0x00000080 // Reboot required to take effect - DI_NEEDREBOOT DI_FLAGS = 0x00000100 // "" - - // Flags for device installation - DI_NOBROWSE DI_FLAGS = 0x00000200 // no Browse... in InsertDisk - - // Flags set by DiBuildDriverInfoList - DI_MULTMFGS DI_FLAGS = 0x00000400 // Set if multiple manufacturers in class driver list - - // Flag indicates that device is disabled - DI_DISABLED DI_FLAGS = 0x00000800 // Set if device disabled - - // Flags for Device/Class Properties - DI_GENERALPAGE_ADDED DI_FLAGS = 0x00001000 - DI_RESOURCEPAGE_ADDED DI_FLAGS = 0x00002000 - - // Flag to indicate the setting properties for this Device (or class) caused a change so the Dev Mgr UI probably needs to be updated. - DI_PROPERTIES_CHANGE DI_FLAGS = 0x00004000 - - // Flag to indicate that the sorting from the INF file should be used. - DI_INF_IS_SORTED DI_FLAGS = 0x00008000 - - // Flag to indicate that only the the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched. - DI_ENUMSINGLEINF DI_FLAGS = 0x00010000 - - // Flag that prevents ConfigMgr from removing/re-enumerating devices during device - // registration, installation, and deletion. - DI_DONOTCALLCONFIGMG DI_FLAGS = 0x00020000 - - // The following flag can be used to install a device disabled - DI_INSTALLDISABLED DI_FLAGS = 0x00040000 - - // Flag that causes SetupDiBuildDriverInfoList to build a device's compatible driver - // list from its existing class driver list, instead of the normal INF search. - DI_COMPAT_FROM_CLASS DI_FLAGS = 0x00080000 - - // This flag is set if the Class Install params should be used. - DI_CLASSINSTALLPARAMS DI_FLAGS = 0x00100000 - - // This flag is set if the caller of DiCallClassInstaller does NOT want the internal default action performed if the Class installer returns ERROR_DI_DO_DEFAULT. - DI_NODI_DEFAULTACTION DI_FLAGS = 0x00200000 - - // Flags for device installation - DI_QUIETINSTALL DI_FLAGS = 0x00800000 // don't confuse the user with questions or excess info - DI_NOFILECOPY DI_FLAGS = 0x01000000 // No file Copy necessary - DI_FORCECOPY DI_FLAGS = 0x02000000 // Force files to be copied from install path - DI_DRIVERPAGE_ADDED DI_FLAGS = 0x04000000 // Prop provider added Driver page. - DI_USECI_SELECTSTRINGS DI_FLAGS = 0x08000000 // Use Class Installer Provided strings in the Select Device Dlg - DI_OVERRIDE_INFFLAGS DI_FLAGS = 0x10000000 // Override INF flags - DI_PROPS_NOCHANGEUSAGE DI_FLAGS = 0x20000000 // No Enable/Disable in General Props - - DI_NOSELECTICONS DI_FLAGS = 0x40000000 // No small icons in select device dialogs - - DI_NOWRITE_IDS DI_FLAGS = 0x80000000 // Don't write HW & Compat IDs on install -) - -// DI_FLAGSEX is SP_DEVINSTALL_PARAMS.FlagsEx values -type DI_FLAGSEX uint32 - -const ( - DI_FLAGSEX_CI_FAILED DI_FLAGSEX = 0x00000004 // Failed to Load/Call class installer - DI_FLAGSEX_FINISHINSTALL_ACTION DI_FLAGSEX = 0x00000008 // Class/co-installer wants to get a DIF_FINISH_INSTALL action in client context. - DI_FLAGSEX_DIDINFOLIST DI_FLAGSEX = 0x00000010 // Did the Class Info List - DI_FLAGSEX_DIDCOMPATINFO DI_FLAGSEX = 0x00000020 // Did the Compat Info List - DI_FLAGSEX_FILTERCLASSES DI_FLAGSEX = 0x00000040 - DI_FLAGSEX_SETFAILEDINSTALL DI_FLAGSEX = 0x00000080 - DI_FLAGSEX_DEVICECHANGE DI_FLAGSEX = 0x00000100 - DI_FLAGSEX_ALWAYSWRITEIDS DI_FLAGSEX = 0x00000200 - DI_FLAGSEX_PROPCHANGE_PENDING DI_FLAGSEX = 0x00000400 // One or more device property sheets have had changes made to them, and need to have a DIF_PROPERTYCHANGE occur. - DI_FLAGSEX_ALLOWEXCLUDEDDRVS DI_FLAGSEX = 0x00000800 - DI_FLAGSEX_NOUIONQUERYREMOVE DI_FLAGSEX = 0x00001000 - DI_FLAGSEX_USECLASSFORCOMPAT DI_FLAGSEX = 0x00002000 // Use the device's class when building compat drv list. (Ignored if DI_COMPAT_FROM_CLASS flag is specified.) - DI_FLAGSEX_NO_DRVREG_MODIFY DI_FLAGSEX = 0x00008000 // Don't run AddReg and DelReg for device's software (driver) key. - DI_FLAGSEX_IN_SYSTEM_SETUP DI_FLAGSEX = 0x00010000 // Installation is occurring during initial system setup. - DI_FLAGSEX_INET_DRIVER DI_FLAGSEX = 0x00020000 // Driver came from Windows Update - DI_FLAGSEX_APPENDDRIVERLIST DI_FLAGSEX = 0x00040000 // Cause SetupDiBuildDriverInfoList to append a new driver list to an existing list. - DI_FLAGSEX_PREINSTALLBACKUP DI_FLAGSEX = 0x00080000 // not used - DI_FLAGSEX_BACKUPONREPLACE DI_FLAGSEX = 0x00100000 // not used - DI_FLAGSEX_DRIVERLIST_FROM_URL DI_FLAGSEX = 0x00200000 // build driver list from INF(s) retrieved from URL specified in SP_DEVINSTALL_PARAMS.DriverPath (empty string means Windows Update website) - DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS DI_FLAGSEX = 0x00800000 // Don't include old Internet drivers when building a driver list. Ignored on Windows Vista and later. - DI_FLAGSEX_POWERPAGE_ADDED DI_FLAGSEX = 0x01000000 // class installer added their own power page - DI_FLAGSEX_FILTERSIMILARDRIVERS DI_FLAGSEX = 0x02000000 // only include similar drivers in class list - DI_FLAGSEX_INSTALLEDDRIVER DI_FLAGSEX = 0x04000000 // only add the installed driver to the class or compat driver list. Used in calls to SetupDiBuildDriverInfoList - DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE DI_FLAGSEX = 0x08000000 // Don't remove identical driver nodes from the class list - DI_FLAGSEX_ALTPLATFORM_DRVSEARCH DI_FLAGSEX = 0x10000000 // Build driver list based on alternate platform information specified in associated file queue - DI_FLAGSEX_RESTART_DEVICE_ONLY DI_FLAGSEX = 0x20000000 // only restart the device drivers are being installed on as opposed to restarting all devices using those drivers. - DI_FLAGSEX_RECURSIVESEARCH DI_FLAGSEX = 0x40000000 // Tell SetupDiBuildDriverInfoList to do a recursive search - DI_FLAGSEX_SEARCH_PUBLISHED_INFS DI_FLAGSEX = 0x80000000 // Tell SetupDiBuildDriverInfoList to do a "published INF" search -) - -// ClassInstallHeader is the first member of any class install parameters structure. It contains the device installation request code that defines the format of the rest of the install parameters structure. -type ClassInstallHeader struct { - size uint32 - InstallFunction DI_FUNCTION -} - -func MakeClassInstallHeader(installFunction DI_FUNCTION) *ClassInstallHeader { - hdr := &ClassInstallHeader{InstallFunction: installFunction} - hdr.size = uint32(unsafe.Sizeof(*hdr)) - return hdr -} - -// DICS_STATE specifies values indicating a change in a device's state -type DICS_STATE uint32 - -const ( - DICS_ENABLE DICS_STATE = 0x00000001 // The device is being enabled. - DICS_DISABLE DICS_STATE = 0x00000002 // The device is being disabled. - DICS_PROPCHANGE DICS_STATE = 0x00000003 // The properties of the device have changed. - DICS_START DICS_STATE = 0x00000004 // The device is being started (if the request is for the currently active hardware profile). - DICS_STOP DICS_STATE = 0x00000005 // The device is being stopped. The driver stack will be unloaded and the CSCONFIGFLAG_DO_NOT_START flag will be set for the device. -) - -// DICS_FLAG specifies the scope of a device property change -type DICS_FLAG uint32 - -const ( - DICS_FLAG_GLOBAL DICS_FLAG = 0x00000001 // make change in all hardware profiles - DICS_FLAG_CONFIGSPECIFIC DICS_FLAG = 0x00000002 // make change in specified profile only - DICS_FLAG_CONFIGGENERAL DICS_FLAG = 0x00000004 // 1 or more hardware profile-specific changes to follow (obsolete) -) - -// PropChangeParams is a structure corresponding to a DIF_PROPERTYCHANGE install function. -type PropChangeParams struct { - ClassInstallHeader ClassInstallHeader - StateChange DICS_STATE - Scope DICS_FLAG - HwProfile uint32 -} - -// DI_REMOVEDEVICE specifies the scope of the device removal -type DI_REMOVEDEVICE uint32 - -const ( - DI_REMOVEDEVICE_GLOBAL DI_REMOVEDEVICE = 0x00000001 // Make this change in all hardware profiles. Remove information about the device from the registry. - DI_REMOVEDEVICE_CONFIGSPECIFIC DI_REMOVEDEVICE = 0x00000002 // Make this change to only the hardware profile specified by HwProfile. this flag only applies to root-enumerated devices. When Windows removes the device from the last hardware profile in which it was configured, Windows performs a global removal. -) - -// RemoveDeviceParams is a structure corresponding to a DIF_REMOVE install function. -type RemoveDeviceParams struct { - ClassInstallHeader ClassInstallHeader - Scope DI_REMOVEDEVICE - HwProfile uint32 -} - -// DrvInfoData is driver information structure (member of a driver info list that may be associated with a particular device instance, or (globally) with a device information set) -type DrvInfoData struct { - size uint32 - DriverType uint32 - _ uintptr - description [LINE_LEN]uint16 - mfgName [LINE_LEN]uint16 - providerName [LINE_LEN]uint16 - DriverDate windows.Filetime - DriverVersion uint64 -} - -func (data *DrvInfoData) Description() string { - return windows.UTF16ToString(data.description[:]) -} - -func (data *DrvInfoData) SetDescription(description string) error { - str, err := windows.UTF16FromString(description) - if err != nil { - return err - } - copy(data.description[:], str) - return nil -} - -func (data *DrvInfoData) MfgName() string { - return windows.UTF16ToString(data.mfgName[:]) -} - -func (data *DrvInfoData) SetMfgName(mfgName string) error { - str, err := windows.UTF16FromString(mfgName) - if err != nil { - return err - } - copy(data.mfgName[:], str) - return nil -} - -func (data *DrvInfoData) ProviderName() string { - return windows.UTF16ToString(data.providerName[:]) -} - -func (data *DrvInfoData) SetProviderName(providerName string) error { - str, err := windows.UTF16FromString(providerName) - if err != nil { - return err - } - copy(data.providerName[:], str) - return nil -} - -// IsNewer method returns true if DrvInfoData date and version is newer than supplied parameters. -func (data *DrvInfoData) IsNewer(driverDate windows.Filetime, driverVersion uint64) bool { - if data.DriverDate.HighDateTime > driverDate.HighDateTime { - return true - } - if data.DriverDate.HighDateTime < driverDate.HighDateTime { - return false - } - - if data.DriverDate.LowDateTime > driverDate.LowDateTime { - return true - } - if data.DriverDate.LowDateTime < driverDate.LowDateTime { - return false - } - - if data.DriverVersion > driverVersion { - return true - } - if data.DriverVersion < driverVersion { - return false - } - - return false -} - -// DrvInfoDetailData is driver information details structure (provides detailed information about a particular driver information structure) -type DrvInfoDetailData struct { - size uint32 // Warning: unsafe.Sizeof(DrvInfoDetailData) > sizeof(SP_DRVINFO_DETAIL_DATA) when GOARCH == 386 => use sizeofDrvInfoDetailData const. - InfDate windows.Filetime - compatIDsOffset uint32 - compatIDsLength uint32 - _ uintptr - sectionName [LINE_LEN]uint16 - infFileName [windows.MAX_PATH]uint16 - drvDescription [LINE_LEN]uint16 - hardwareID [ANYSIZE_ARRAY]uint16 -} - -func (data *DrvInfoDetailData) SectionName() string { - return windows.UTF16ToString(data.sectionName[:]) -} - -func (data *DrvInfoDetailData) InfFileName() string { - return windows.UTF16ToString(data.infFileName[:]) -} - -func (data *DrvInfoDetailData) DrvDescription() string { - return windows.UTF16ToString(data.drvDescription[:]) -} - -func (data *DrvInfoDetailData) HardwareID() string { - if data.compatIDsOffset > 1 { - bufW := data.getBuf() - return windows.UTF16ToString(bufW[:wcslen(bufW)]) - } - - return "" -} - -func (data *DrvInfoDetailData) CompatIDs() []string { - a := make([]string, 0) - - if data.compatIDsLength > 0 { - bufW := data.getBuf() - bufW = bufW[data.compatIDsOffset : data.compatIDsOffset+data.compatIDsLength] - for i := 0; i < len(bufW); { - j := i + wcslen(bufW[i:]) - if i < j { - a = append(a, windows.UTF16ToString(bufW[i:j])) - } - i = j + 1 - } - } - - return a -} - -func (data *DrvInfoDetailData) getBuf() []uint16 { - len := (data.size - uint32(unsafe.Offsetof(data.hardwareID))) / 2 - sl := struct { - addr *uint16 - len int - cap int - }{&data.hardwareID[0], int(len), int(len)} - return *(*[]uint16)(unsafe.Pointer(&sl)) -} - -// IsCompatible method tests if given hardware ID matches the driver or is listed on the compatible ID list. -func (data *DrvInfoDetailData) IsCompatible(hwid string) bool { - hwidLC := strings.ToLower(hwid) - if strings.ToLower(data.HardwareID()) == hwidLC { - return true - } - a := data.CompatIDs() - for i := range a { - if strings.ToLower(a[i]) == hwidLC { - return true - } - } - - return false -} - -// DICD flags control SetupDiCreateDeviceInfo -type DICD uint32 - -const ( - DICD_GENERATE_ID DICD = 0x00000001 - DICD_INHERIT_CLASSDRVS DICD = 0x00000002 -) - -// -// SPDIT flags to distinguish between class drivers and -// device drivers. -// (Passed in 'DriverType' parameter of driver information list APIs) -// -type SPDIT uint32 - -const ( - SPDIT_NODRIVER SPDIT = 0x00000000 - SPDIT_CLASSDRIVER SPDIT = 0x00000001 - SPDIT_COMPATDRIVER SPDIT = 0x00000002 -) - -// DIGCF flags control what is included in the device information set built by SetupDiGetClassDevs -type DIGCF uint32 - -const ( - DIGCF_DEFAULT DIGCF = 0x00000001 // only valid with DIGCF_DEVICEINTERFACE - DIGCF_PRESENT DIGCF = 0x00000002 - DIGCF_ALLCLASSES DIGCF = 0x00000004 - DIGCF_PROFILE DIGCF = 0x00000008 - DIGCF_DEVICEINTERFACE DIGCF = 0x00000010 -) - -// DIREG specifies values for SetupDiCreateDevRegKey, SetupDiOpenDevRegKey, and SetupDiDeleteDevRegKey. -type DIREG uint32 - -const ( - DIREG_DEV DIREG = 0x00000001 // Open/Create/Delete device key - DIREG_DRV DIREG = 0x00000002 // Open/Create/Delete driver key - DIREG_BOTH DIREG = 0x00000004 // Delete both driver and Device key -) - -// -// SPDRP specifies device registry property codes -// (Codes marked as read-only (R) may only be used for -// SetupDiGetDeviceRegistryProperty) -// -// These values should cover the same set of registry properties -// as defined by the CM_DRP codes in cfgmgr32.h. -// -// Note that SPDRP codes are zero based while CM_DRP codes are one based! -// -type SPDRP uint32 - -const ( - SPDRP_DEVICEDESC SPDRP = 0x00000000 // DeviceDesc (R/W) - SPDRP_HARDWAREID SPDRP = 0x00000001 // HardwareID (R/W) - SPDRP_COMPATIBLEIDS SPDRP = 0x00000002 // CompatibleIDs (R/W) - SPDRP_SERVICE SPDRP = 0x00000004 // Service (R/W) - SPDRP_CLASS SPDRP = 0x00000007 // Class (R--tied to ClassGUID) - SPDRP_CLASSGUID SPDRP = 0x00000008 // ClassGUID (R/W) - SPDRP_DRIVER SPDRP = 0x00000009 // Driver (R/W) - SPDRP_CONFIGFLAGS SPDRP = 0x0000000A // ConfigFlags (R/W) - SPDRP_MFG SPDRP = 0x0000000B // Mfg (R/W) - SPDRP_FRIENDLYNAME SPDRP = 0x0000000C // FriendlyName (R/W) - SPDRP_LOCATION_INFORMATION SPDRP = 0x0000000D // LocationInformation (R/W) - SPDRP_PHYSICAL_DEVICE_OBJECT_NAME SPDRP = 0x0000000E // PhysicalDeviceObjectName (R) - SPDRP_CAPABILITIES SPDRP = 0x0000000F // Capabilities (R) - SPDRP_UI_NUMBER SPDRP = 0x00000010 // UiNumber (R) - SPDRP_UPPERFILTERS SPDRP = 0x00000011 // UpperFilters (R/W) - SPDRP_LOWERFILTERS SPDRP = 0x00000012 // LowerFilters (R/W) - SPDRP_BUSTYPEGUID SPDRP = 0x00000013 // BusTypeGUID (R) - SPDRP_LEGACYBUSTYPE SPDRP = 0x00000014 // LegacyBusType (R) - SPDRP_BUSNUMBER SPDRP = 0x00000015 // BusNumber (R) - SPDRP_ENUMERATOR_NAME SPDRP = 0x00000016 // Enumerator Name (R) - SPDRP_SECURITY SPDRP = 0x00000017 // Security (R/W, binary form) - SPDRP_SECURITY_SDS SPDRP = 0x00000018 // Security (W, SDS form) - SPDRP_DEVTYPE SPDRP = 0x00000019 // Device Type (R/W) - SPDRP_EXCLUSIVE SPDRP = 0x0000001A // Device is exclusive-access (R/W) - SPDRP_CHARACTERISTICS SPDRP = 0x0000001B // Device Characteristics (R/W) - SPDRP_ADDRESS SPDRP = 0x0000001C // Device Address (R) - SPDRP_UI_NUMBER_DESC_FORMAT SPDRP = 0x0000001D // UiNumberDescFormat (R/W) - SPDRP_DEVICE_POWER_DATA SPDRP = 0x0000001E // Device Power Data (R) - SPDRP_REMOVAL_POLICY SPDRP = 0x0000001F // Removal Policy (R) - SPDRP_REMOVAL_POLICY_HW_DEFAULT SPDRP = 0x00000020 // Hardware Removal Policy (R) - SPDRP_REMOVAL_POLICY_OVERRIDE SPDRP = 0x00000021 // Removal Policy Override (RW) - SPDRP_INSTALL_STATE SPDRP = 0x00000022 // Device Install State (R) - SPDRP_LOCATION_PATHS SPDRP = 0x00000023 // Device Location Paths (R) - SPDRP_BASE_CONTAINERID SPDRP = 0x00000024 // Base ContainerID (R) - - SPDRP_MAXIMUM_PROPERTY SPDRP = 0x00000025 // Upper bound on ordinals -) - -const ( - CR_SUCCESS = 0x0 - CR_BUFFER_SMALL = 0x1a -) - -const ( - CM_GET_DEVICE_INTERFACE_LIST_PRESENT = 0 // only currently 'live' device interfaces - CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES = 1 // all registered device interfaces, live or not -) diff --git a/tun/wintun/setupapi/zsetupapi_windows.go b/tun/wintun/setupapi/zsetupapi_windows.go deleted file mode 100644 index 375862d..0000000 --- a/tun/wintun/setupapi/zsetupapi_windows.go +++ /dev/null @@ -1,398 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package setupapi - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -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 -} - -var ( - modsetupapi = windows.NewLazySystemDLL("setupapi.dll") - modCfgMgr32 = windows.NewLazySystemDLL("CfgMgr32.dll") - - procSetupDiCreateDeviceInfoListExW = modsetupapi.NewProc("SetupDiCreateDeviceInfoListExW") - procSetupDiGetDeviceInfoListDetailW = modsetupapi.NewProc("SetupDiGetDeviceInfoListDetailW") - procSetupDiCreateDeviceInfoW = modsetupapi.NewProc("SetupDiCreateDeviceInfoW") - procSetupDiEnumDeviceInfo = modsetupapi.NewProc("SetupDiEnumDeviceInfo") - procSetupDiDestroyDeviceInfoList = modsetupapi.NewProc("SetupDiDestroyDeviceInfoList") - procSetupDiBuildDriverInfoList = modsetupapi.NewProc("SetupDiBuildDriverInfoList") - procSetupDiCancelDriverInfoSearch = modsetupapi.NewProc("SetupDiCancelDriverInfoSearch") - procSetupDiEnumDriverInfoW = modsetupapi.NewProc("SetupDiEnumDriverInfoW") - procSetupDiGetSelectedDriverW = modsetupapi.NewProc("SetupDiGetSelectedDriverW") - procSetupDiSetSelectedDriverW = modsetupapi.NewProc("SetupDiSetSelectedDriverW") - procSetupDiGetDriverInfoDetailW = modsetupapi.NewProc("SetupDiGetDriverInfoDetailW") - procSetupDiDestroyDriverInfoList = modsetupapi.NewProc("SetupDiDestroyDriverInfoList") - procSetupDiGetClassDevsExW = modsetupapi.NewProc("SetupDiGetClassDevsExW") - procSetupDiCallClassInstaller = modsetupapi.NewProc("SetupDiCallClassInstaller") - procSetupDiOpenDevRegKey = modsetupapi.NewProc("SetupDiOpenDevRegKey") - procSetupDiGetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiGetDeviceRegistryPropertyW") - procSetupDiSetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiSetDeviceRegistryPropertyW") - procSetupDiGetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiGetDeviceInstallParamsW") - procSetupDiGetDeviceInstanceIdW = modsetupapi.NewProc("SetupDiGetDeviceInstanceIdW") - procSetupDiGetClassInstallParamsW = modsetupapi.NewProc("SetupDiGetClassInstallParamsW") - procSetupDiSetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiSetDeviceInstallParamsW") - procSetupDiSetClassInstallParamsW = modsetupapi.NewProc("SetupDiSetClassInstallParamsW") - procSetupDiClassNameFromGuidExW = modsetupapi.NewProc("SetupDiClassNameFromGuidExW") - procSetupDiClassGuidsFromNameExW = modsetupapi.NewProc("SetupDiClassGuidsFromNameExW") - procSetupDiGetSelectedDevice = modsetupapi.NewProc("SetupDiGetSelectedDevice") - procSetupDiSetSelectedDevice = modsetupapi.NewProc("SetupDiSetSelectedDevice") - procCM_Get_Device_Interface_List_SizeW = modCfgMgr32.NewProc("CM_Get_Device_Interface_List_SizeW") - procCM_Get_Device_Interface_ListW = modCfgMgr32.NewProc("CM_Get_Device_Interface_ListW") -) - -func setupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { - r0, _, e1 := syscall.Syscall6(procSetupDiCreateDeviceInfoListExW.Addr(), 4, uintptr(unsafe.Pointer(classGUID)), uintptr(hwndParent), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) - handle = DevInfo(r0) - if handle == DevInfo(windows.InvalidHandle) { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInfoListDetailW.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoSetDetailData)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *windows.GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall9(procSetupDiCreateDeviceInfoW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(DeviceName)), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(DeviceDescription)), uintptr(hwndParent), uintptr(CreationFlags), uintptr(unsafe.Pointer(deviceInfoData)), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiEnumDeviceInfo.Addr(), 3, uintptr(deviceInfoSet), uintptr(memberIndex), uintptr(unsafe.Pointer(deviceInfoData))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiDestroyDeviceInfoList.Addr(), 1, uintptr(deviceInfoSet), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiBuildDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiCancelDriverInfoSearch.Addr(), 1, uintptr(deviceInfoSet), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiEnumDriverInfoW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType), uintptr(memberIndex), uintptr(unsafe.Pointer(driverInfoData)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetDriverInfoDetailW.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)), uintptr(unsafe.Pointer(driverInfoDetailData)), uintptr(driverInfoDetailDataSize), uintptr(unsafe.Pointer(requiredSize))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiDestroyDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetClassDevsEx(classGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { - r0, _, e1 := syscall.Syscall9(procSetupDiGetClassDevsExW.Addr(), 7, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) - handle = DevInfo(r0) - if handle == DevInfo(windows.InvalidHandle) { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiCallClassInstaller.Addr(), 3, uintptr(installFunction), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key windows.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procSetupDiOpenDevRegKey.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(Scope), uintptr(HwProfile), uintptr(KeyType), uintptr(samDesired)) - key = windows.Handle(r0) - if key == windows.InvalidHandle { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procSetupDiGetDeviceRegistryPropertyW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyRegDataType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiSetDeviceRegistryPropertyW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetDeviceInstanceIdW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(instanceId)), uintptr(instanceIdSize), uintptr(unsafe.Pointer(instanceIdRequiredSize)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiGetClassInstallParamsW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), uintptr(unsafe.Pointer(requiredSize)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiSetClassInstallParamsW.Addr(), 4, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), 0, 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiClassNameFromGuidEx(classGUID *windows.GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiClassNameFromGuidExW.Addr(), 6, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(className)), uintptr(classNameSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiClassGuidsFromNameEx(className *uint16, classGuidList *windows.GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procSetupDiClassGuidsFromNameExW.Addr(), 6, uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(classGuidList)), uintptr(classGuidListSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { - r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) - if r1 == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - -func cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *windows.GUID, deviceID *uint16, flags uint32) (ret uint32) { - r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_List_SizeW.Addr(), 4, uintptr(unsafe.Pointer(len)), uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(flags), 0, 0) - ret = uint32(r0) - return -} - -func cm_Get_Device_Interface_List(interfaceClass *windows.GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret uint32) { - r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_ListW.Addr(), 5, uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(flags), 0) - ret = uint32(r0) - return -} diff --git a/tun/wintun/setupapi/zsetupapi_windows_test.go b/tun/wintun/setupapi/zsetupapi_windows_test.go deleted file mode 100644 index 5b5f369..0000000 --- a/tun/wintun/setupapi/zsetupapi_windows_test.go +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2020 WireGuard LLC. All Rights Reserved. - */ - -package setupapi - -import ( - "syscall" - "testing" - - "golang.org/x/sys/windows" -) - -func TestSetupDiDestroyDeviceInfoList(t *testing.T) { - err := SetupDiDestroyDeviceInfoList(DevInfo(windows.InvalidHandle)) - if errWin, ok := err.(syscall.Errno); !ok || errWin != windows.ERROR_INVALID_HANDLE { - t.Errorf("SetupDiDestroyDeviceInfoList(nil, ...) should fail with ERROR_INVALID_HANDLE") - } -} diff --git a/tun/wintun/wintun_windows.go b/tun/wintun/wintun_windows.go index eed4f01..14b0260 100644 --- a/tun/wintun/wintun_windows.go +++ b/tun/wintun/wintun_windows.go @@ -7,814 +7,221 @@ package wintun import ( "errors" - "fmt" - "strings" - "time" + "log" + "runtime" + "syscall" "unsafe" "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" - - "golang.zx2c4.com/wireguard/tun/wintun/iphlpapi" - "golang.zx2c4.com/wireguard/tun/wintun/nci" - registryEx "golang.zx2c4.com/wireguard/tun/wintun/registry" - "golang.zx2c4.com/wireguard/tun/wintun/setupapi" ) -type Pool string - -type Interface struct { - cfgInstanceID windows.GUID - devInstanceID string - luidIndex uint32 - ifType uint32 - pool Pool -} - -var deviceClassNetGUID = windows.GUID{Data1: 0x4d36e972, Data2: 0xe325, Data3: 0x11ce, Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}} -var deviceInterfaceNetGUID = windows.GUID{Data1: 0xcac88484, Data2: 0x7515, Data3: 0x4c03, Data4: [8]byte{0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}} +type loggerLevel int const ( - hardwareID = "Wintun" - waitForRegistryTimeout = time.Second * 10 + logInfo loggerLevel = iota + logWarn + logErr ) -// makeWintun creates a Wintun interface handle and populates it from the device's registry key. -func makeWintun(devInfo setupapi.DevInfo, devInfoData *setupapi.DevInfoData, pool Pool) (*Interface, error) { - // Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key. - key, err := devInfo.OpenDevRegKey(devInfoData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.QUERY_VALUE) - if err != nil { - return nil, fmt.Errorf("Device-specific registry key open failed: %v", err) - } - defer key.Close() - - // Read the NetCfgInstanceId value. - valueStr, err := registryEx.GetStringValue(key, "NetCfgInstanceId") - if err != nil { - return nil, fmt.Errorf("RegQueryStringValue(\"NetCfgInstanceId\") failed: %v", err) - } - - // Convert to GUID. - ifid, err := windows.GUIDFromString(valueStr) - if err != nil { - return nil, fmt.Errorf("NetCfgInstanceId registry value is not a GUID (expected: \"{...}\", provided: %q)", valueStr) - } - - // Read the NetLuidIndex value. - luidIdx, _, err := key.GetIntegerValue("NetLuidIndex") - if err != nil { - return nil, fmt.Errorf("RegQueryValue(\"NetLuidIndex\") failed: %v", err) - } - - // Read the NetLuidIndex value. - ifType, _, err := key.GetIntegerValue("*IfType") - if err != nil { - return nil, fmt.Errorf("RegQueryValue(\"*IfType\") failed: %v", err) - } - - instanceID, err := devInfo.DeviceInstanceID(devInfoData) - if err != nil { - return nil, fmt.Errorf("DeviceInstanceID failed: %v", err) - } - - return &Interface{ - cfgInstanceID: ifid, - devInstanceID: instanceID, - luidIndex: uint32(luidIdx), - ifType: uint32(ifType), - pool: pool, - }, nil -} - -func removeNumberedSuffix(ifname string) string { - removed := strings.TrimRight(ifname, "0123456789") - if removed != ifname && len(removed) > 1 && removed[len(removed)-1] == ' ' { - return removed[:len(removed)-1] - } - return ifname -} - -// GetInterface finds a Wintun interface by its name. This function returns -// the interface if found, or windows.ERROR_OBJECT_NOT_FOUND otherwise. If -// the interface is found but not a Wintun-class or a member of the pool, -// this function returns windows.ERROR_ALREADY_EXISTS. -func (pool Pool) GetInterface(ifname string) (*Interface, error) { - mutex, err := pool.takeNameMutex() - if err != nil { - return nil, err - } - defer func() { - windows.ReleaseMutex(mutex) - windows.CloseHandle(mutex) - }() - - // Create a list of network devices. - devInfo, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "") - if err != nil { - return nil, fmt.Errorf("SetupDiGetClassDevsEx(%v) failed: %v", deviceClassNetGUID, err) - } - defer devInfo.Close() - - // Windows requires each interface to have a different name. When - // enforcing this, Windows treats interface names case-insensitive. If an - // interface "FooBar" exists and this function reports there is no - // interface "foobar", an attempt to create a new interface and name it - // "foobar" would cause conflict with "FooBar". - ifname = strings.ToLower(ifname) - - for index := 0; ; index++ { - devInfoData, err := devInfo.EnumDeviceInfo(index) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - // Check the Hardware ID to make sure it's a real Wintun device first. This avoids doing slow operations on non-Wintun devices. - property, err := devInfo.DeviceRegistryProperty(devInfoData, setupapi.SPDRP_HARDWAREID) - if err != nil { - continue - } - if !isOurHardwareID(property) { - continue - } - - wintun, err := makeWintun(devInfo, devInfoData, pool) - if err != nil { - continue - } - - // TODO: is there a better way than comparing ifnames? - ifname2, err := wintun.Name() - if err != nil { - continue - } - ifname2 = strings.ToLower(ifname2) - ifname3 := removeNumberedSuffix(ifname2) - - if ifname == ifname2 || ifname == ifname3 { - err = devInfo.BuildDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) - if err != nil { - return nil, fmt.Errorf("SetupDiBuildDriverInfoList failed: %v", err) - } - defer devInfo.DestroyDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) - - for index := 0; ; index++ { - driverData, err := devInfo.EnumDriverInfo(devInfoData, setupapi.SPDIT_COMPATDRIVER, index) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - // Get driver info details. - driverDetailData, err := devInfo.DriverInfoDetail(devInfoData, driverData) - if err != nil { - continue - } - - if driverDetailData.IsCompatible(hardwareID) { - isMember, err := pool.isMember(devInfo, devInfoData) - if err != nil { - return nil, err - } - if !isMember { - return nil, windows.ERROR_ALREADY_EXISTS - } - - return wintun, nil - } - } +const ( + PoolNameMax = 256 + AdapterNameMax = 128 +) - // This interface is not using Wintun driver. - return nil, windows.ERROR_ALREADY_EXISTS - } - } +type Pool [PoolNameMax]uint16 +type Adapter struct { + handle uintptr +} + +var ( + modwintun = windows.NewLazyDLL("wintun.dll") + + procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter") + procWintunDeleteAdapter = modwintun.NewProc("WintunDeleteAdapter") + procWintunDeletePoolDriver = modwintun.NewProc("WintunDeletePoolDriver") + procWintunEnumAdapters = modwintun.NewProc("WintunEnumAdapters") + procWintunFreeAdapter = modwintun.NewProc("WintunFreeAdapter") + procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter") + procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID") + procWintunGetAdapterName = modwintun.NewProc("WintunGetAdapterName") + procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion") + procWintunOpenAdapterDeviceObject = modwintun.NewProc("WintunOpenAdapterDeviceObject") + procWintunSetAdapterName = modwintun.NewProc("WintunSetAdapterName") + procWintunSetLogger = modwintun.NewProc("WintunSetLogger") +) - return nil, windows.ERROR_OBJECT_NOT_FOUND +func init() { + syscall.Syscall(procWintunSetLogger.Addr(), 1, windows.NewCallback(func(level loggerLevel, msg *uint16) int { + log.Println("[Wintun]", windows.UTF16PtrToString(msg)) + return 0 + }), 0, 0) } -// CreateInterface creates a Wintun interface. ifname is the requested name of -// the interface, while requestedGUID is the GUID of the created network -// interface, which then influences NLA generation deterministically. If it is -// set to nil, the GUID is chosen by the system at random, and hence a new NLA -// entry is created for each new interface. It is called "requested" GUID -// because the API it uses is completely undocumented, and so there could be minor -// interesting complications with its usage. This function returns the network -// interface ID and a flag if reboot is required. -func (pool Pool) CreateInterface(ifname string, requestedGUID *windows.GUID) (wintun *Interface, rebootRequired bool, err error) { - mutex, err := pool.takeNameMutex() - if err != nil { - return - } - defer func() { - windows.ReleaseMutex(mutex) - windows.CloseHandle(mutex) - }() - - // Create an empty device info set for network adapter device class. - devInfo, err := setupapi.SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, "") - if err != nil { - err = fmt.Errorf("SetupDiCreateDeviceInfoListEx(%v) failed: %v", deviceClassNetGUID, err) - return - } - defer devInfo.Close() - - // Get the device class name from GUID. - className, err := setupapi.SetupDiClassNameFromGuidEx(&deviceClassNetGUID, "") - if err != nil { - err = fmt.Errorf("SetupDiClassNameFromGuidEx(%v) failed: %v", deviceClassNetGUID, err) - return - } - - // Create a new device info element and add it to the device info set. - deviceTypeName := pool.deviceTypeName() - devInfoData, err := devInfo.CreateDeviceInfo(className, &deviceClassNetGUID, deviceTypeName, 0, setupapi.DICD_GENERATE_ID) +func MakePool(poolName string) (pool *Pool, err error) { + poolName16, err := windows.UTF16FromString(poolName) if err != nil { - err = fmt.Errorf("SetupDiCreateDeviceInfo failed: %v", err) return } - - err = setQuietInstall(devInfo, devInfoData) - if err != nil { - err = fmt.Errorf("Setting quiet installation failed: %v", err) - return - } - - // Set a device information element as the selected member of a device information set. - err = devInfo.SetSelectedDevice(devInfoData) - if err != nil { - err = fmt.Errorf("SetupDiSetSelectedDevice failed: %v", err) - return - } - - // Set Plug&Play device hardware ID property. - err = devInfo.SetDeviceRegistryPropertyString(devInfoData, setupapi.SPDRP_HARDWAREID, hardwareID) - if err != nil { - err = fmt.Errorf("SetupDiSetDeviceRegistryProperty(SPDRP_HARDWAREID) failed: %v", err) - return - } - - err = devInfo.BuildDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) // TODO: This takes ~510ms - if err != nil { - err = fmt.Errorf("SetupDiBuildDriverInfoList failed: %v", err) - return - } - defer devInfo.DestroyDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) - - driverDate := windows.Filetime{} - driverVersion := uint64(0) - for index := 0; ; index++ { // TODO: This loop takes ~600ms - driverData, err := devInfo.EnumDriverInfo(devInfoData, setupapi.SPDIT_COMPATDRIVER, index) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - // Check the driver version first, since the check is trivial and will save us iterating over hardware IDs for any driver versioned prior our best match. - if driverData.IsNewer(driverDate, driverVersion) { - driverDetailData, err := devInfo.DriverInfoDetail(devInfoData, driverData) - if err != nil { - continue - } - - if driverDetailData.IsCompatible(hardwareID) { - err := devInfo.SetSelectedDriver(devInfoData, driverData) - if err != nil { - continue - } - - driverDate = driverData.DriverDate - driverVersion = driverData.DriverVersion - } - } - } - - if driverVersion == 0 { - err = fmt.Errorf("No driver for device %q installed", hardwareID) - return - } - - defer func() { - if err != nil { - // The interface failed to install, or the interface ID was unobtainable. Clean-up. - removeDeviceParams := setupapi.RemoveDeviceParams{ - ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE), - Scope: setupapi.DI_REMOVEDEVICE_GLOBAL, - } - - // Set class installer parameters for DIF_REMOVE. - if devInfo.SetClassInstallParams(devInfoData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams))) == nil { - // Call appropriate class installer. - if devInfo.CallClassInstaller(setupapi.DIF_REMOVE, devInfoData) == nil { - rebootRequired = rebootRequired || checkReboot(devInfo, devInfoData) - } - } - - wintun = nil - } - }() - - // Call appropriate class installer. - err = devInfo.CallClassInstaller(setupapi.DIF_REGISTERDEVICE, devInfoData) - if err != nil { - err = fmt.Errorf("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed: %v", err) - return - } - - // Register device co-installers if any. (Ignore errors) - devInfo.CallClassInstaller(setupapi.DIF_REGISTER_COINSTALLERS, devInfoData) - - var netDevRegKey registry.Key - const pollTimeout = time.Millisecond * 50 - for i := 0; i < int(waitForRegistryTimeout/pollTimeout); i++ { - if i != 0 { - time.Sleep(pollTimeout) - } - netDevRegKey, err = devInfo.OpenDevRegKey(devInfoData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.SET_VALUE|registry.QUERY_VALUE|registry.NOTIFY) - if err == nil { - break - } - } - if err != nil { - err = fmt.Errorf("SetupDiOpenDevRegKey failed: %v", err) - return - } - defer netDevRegKey.Close() - if requestedGUID != nil { - err = netDevRegKey.SetStringValue("NetSetupAnticipatedInstanceId", requestedGUID.String()) - if err != nil { - err = fmt.Errorf("SetStringValue(NetSetupAnticipatedInstanceId) failed: %v", err) - return - } - } - - // Install interfaces if any. (Ignore errors) - devInfo.CallClassInstaller(setupapi.DIF_INSTALLINTERFACES, devInfoData) - - // Install the device. - err = devInfo.CallClassInstaller(setupapi.DIF_INSTALLDEVICE, devInfoData) - if err != nil { - err = fmt.Errorf("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed: %v", err) - return - } - rebootRequired = checkReboot(devInfo, devInfoData) - - err = devInfo.SetDeviceRegistryPropertyString(devInfoData, setupapi.SPDRP_DEVICEDESC, deviceTypeName) - if err != nil { - err = fmt.Errorf("SetDeviceRegistryPropertyString(SPDRP_DEVICEDESC) failed: %v", err) + if len(poolName16) > PoolNameMax { + err = errors.New("Pool name too long") return } + pool = &Pool{} + copy(pool[:], poolName16) + return +} - // DIF_INSTALLDEVICE returns almost immediately, while the device installation - // continues in the background. It might take a while, before all registry - // keys and values are populated. - _, err = registryEx.GetStringValueWait(netDevRegKey, "NetCfgInstanceId", waitForRegistryTimeout) - if err != nil { - err = fmt.Errorf("GetStringValueWait(NetCfgInstanceId) failed: %v", err) - return - } - _, err = registryEx.GetIntegerValueWait(netDevRegKey, "NetLuidIndex", waitForRegistryTimeout) - if err != nil { - err = fmt.Errorf("GetIntegerValueWait(NetLuidIndex) failed: %v", err) - return - } - _, err = registryEx.GetIntegerValueWait(netDevRegKey, "*IfType", waitForRegistryTimeout) - if err != nil { - err = fmt.Errorf("GetIntegerValueWait(*IfType) failed: %v", err) - return - } +func (pool *Pool) String() string { + return windows.UTF16ToString(pool[:]) +} - // Get network interface. - wintun, err = makeWintun(devInfo, devInfoData, pool) - if err != nil { - err = fmt.Errorf("makeWintun failed: %v", err) - return - } +func freeAdapter(wintun *Adapter) { + syscall.Syscall(procWintunFreeAdapter.Addr(), 1, uintptr(wintun.handle), 0, 0) +} - // Wait for TCP/IP adapter registry key to emerge and populate. - tcpipAdapterRegKey, err := registryEx.OpenKeyWait( - registry.LOCAL_MACHINE, - wintun.tcpipAdapterRegKeyName(), registry.QUERY_VALUE|registry.NOTIFY, - waitForRegistryTimeout) +// OpenAdapter finds a Wintun adapter by its name. This function returns the adapter if found, or +// windows.ERROR_FILE_NOT_FOUND otherwise. If the adapter is found but not a Wintun-class or a +// member of the pool, this function returns windows.ERROR_ALREADY_EXISTS. The adapter must be +// released after use. +func (pool *Pool) OpenAdapter(ifname string) (wintun *Adapter, err error) { + ifname16, err := windows.UTF16PtrFromString(ifname) if err != nil { - err = fmt.Errorf("OpenKeyWait(HKLM\\%s) failed: %v", wintun.tcpipAdapterRegKeyName(), err) - return - } - defer tcpipAdapterRegKey.Close() - _, err = registryEx.GetStringValueWait(tcpipAdapterRegKey, "IpConfig", waitForRegistryTimeout) - if err != nil { - err = fmt.Errorf("GetStringValueWait(IpConfig) failed: %v", err) - return + return nil, err } - - tcpipInterfaceRegKeyName, err := wintun.tcpipInterfaceRegKeyName() - if err != nil { - err = fmt.Errorf("tcpipInterfaceRegKeyName failed: %v", err) + r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 2, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(ifname16)), 0) + if r0 == 0 { + err = e1 return } + wintun = &Adapter{r0} + runtime.SetFinalizer(wintun, freeAdapter) + return +} - // Wait for TCP/IP interface registry key to emerge. - tcpipInterfaceRegKey, err := registryEx.OpenKeyWait( - registry.LOCAL_MACHINE, - tcpipInterfaceRegKeyName, registry.QUERY_VALUE|registry.SET_VALUE, - waitForRegistryTimeout) +// CreateAdapter creates a Wintun adapter. ifname is the requested name of the adapter, while +// requestedGUID is the GUID of the created network adapter, which then influences NLA generation +// deterministically. If it is set to nil, the GUID is chosen by the system at random, and hence a +// new NLA entry is created for each new adapter. It is called "requested" GUID because the API it +// uses is completely undocumented, and so there could be minor interesting complications with its +// usage. This function returns the network adapter ID and a flag if reboot is required. +func (pool *Pool) CreateAdapter(ifname string, requestedGUID *windows.GUID) (wintun *Adapter, rebootRequired bool, err error) { + var ifname16 *uint16 + ifname16, err = windows.UTF16PtrFromString(ifname) if err != nil { - err = fmt.Errorf("OpenKeyWait(HKLM\\%s) failed: %v", tcpipInterfaceRegKeyName, err) return } - defer tcpipInterfaceRegKey.Close() - // Disable dead gateway detection on our interface. - tcpipInterfaceRegKey.SetDWordValue("EnableDeadGWDetect", 0) - - err = wintun.SetName(ifname) - if err != nil { - err = fmt.Errorf("Unable to set name of Wintun interface: %v", err) + var _p0 uint32 + r0, _, e1 := syscall.Syscall6(procWintunCreateAdapter.Addr(), 4, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(ifname16)), uintptr(unsafe.Pointer(requestedGUID)), uintptr(unsafe.Pointer(&_p0)), 0, 0) + rebootRequired = _p0 != 0 + if r0 == 0 { + err = e1 return } - + wintun = &Adapter{r0} + runtime.SetFinalizer(wintun, freeAdapter) return } -// DeleteInterface deletes a Wintun interface. This function succeeds -// if the interface was not found. It returns a bool indicating whether -// a reboot is required. -func (wintun *Interface) DeleteInterface() (rebootRequired bool, err error) { - devInfo, devInfoData, err := wintun.devInfoData() - if err == windows.ERROR_OBJECT_NOT_FOUND { - return false, nil +// Delete deletes a Wintun adapter. This function succeeds if the adapter was not found. It returns +// a bool indicating whether a reboot is required. +func (wintun *Adapter) Delete(forceCloseSessions bool) (rebootRequired bool, err error) { + var _p0 uint32 + if forceCloseSessions { + _p0 = 1 } - if err != nil { - return false, err + var _p1 uint32 + r1, _, e1 := syscall.Syscall(procWintunDeleteAdapter.Addr(), 3, uintptr(wintun.handle), uintptr(_p0), uintptr(unsafe.Pointer(&_p1))) + rebootRequired = _p1 != 0 + if r1 == 0 { + err = e1 } - defer devInfo.Close() - - // Remove the device. - removeDeviceParams := setupapi.RemoveDeviceParams{ - ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE), - Scope: setupapi.DI_REMOVEDEVICE_GLOBAL, - } - - // Set class installer parameters for DIF_REMOVE. - err = devInfo.SetClassInstallParams(devInfoData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams))) - if err != nil { - return false, fmt.Errorf("SetupDiSetClassInstallParams failed: %v", err) - } - - // Call appropriate class installer. - err = devInfo.CallClassInstaller(setupapi.DIF_REMOVE, devInfoData) - if err != nil { - return false, fmt.Errorf("SetupDiCallClassInstaller failed: %v", err) - } - - return checkReboot(devInfo, devInfoData), nil + return } -// DeleteMatchingInterfaces deletes all Wintun interfaces, which match +// DeleteMatchingAdapters deletes all Wintun adapters, which match // given criteria, and returns which ones it deleted, whether a reboot // is required after, and which errors occurred during the process. -func (pool Pool) DeleteMatchingInterfaces(matches func(wintun *Interface) bool) (deviceInstancesDeleted []uint32, rebootRequired bool, errors []error) { - mutex, err := pool.takeNameMutex() - if err != nil { - errors = append(errors, err) - return - } - defer func() { - windows.ReleaseMutex(mutex) - windows.CloseHandle(mutex) - }() - - devInfo, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "") - if err != nil { - return nil, false, []error{fmt.Errorf("SetupDiGetClassDevsEx(%v) failed: %v", deviceClassNetGUID, err.Error())} - } - defer devInfo.Close() - - for i := 0; ; i++ { - devInfoData, err := devInfo.EnumDeviceInfo(i) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue +func (pool *Pool) DeleteMatchingAdapters(matches func(adapter *Adapter) bool, forceCloseSessions bool) (rebootRequired bool, errors []error) { + cb := func(handle uintptr, _ uintptr) int { + adapter := &Adapter{handle} + if !matches(adapter) { + return 1 } - - // Check the Hardware ID to make sure it's a real Wintun device first. This avoids doing slow operations on non-Wintun devices. - property, err := devInfo.DeviceRegistryProperty(devInfoData, setupapi.SPDRP_HARDWAREID) - if err != nil { - continue - } - if !isOurHardwareID(property) { - continue - } - - err = devInfo.BuildDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) - if err != nil { - continue - } - defer devInfo.DestroyDriverInfoList(devInfoData, setupapi.SPDIT_COMPATDRIVER) - - isWintun := false - for j := 0; ; j++ { - driverData, err := devInfo.EnumDriverInfo(devInfoData, setupapi.SPDIT_COMPATDRIVER, j) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - driverDetailData, err := devInfo.DriverInfoDetail(devInfoData, driverData) - if err != nil { - continue - } - if driverDetailData.IsCompatible(hardwareID) { - isWintun = true - break - } - } - if !isWintun { - continue - } - - isMember, err := pool.isMember(devInfo, devInfoData) - if err != nil { - errors = append(errors, err) - continue - } - if !isMember { - continue - } - - wintun, err := makeWintun(devInfo, devInfoData, pool) - if err != nil { - errors = append(errors, fmt.Errorf("Unable to make Wintun interface object: %v", err)) - continue - } - if !matches(wintun) { - continue - } - - err = setQuietInstall(devInfo, devInfoData) + rebootRequired2, err := adapter.Delete(forceCloseSessions) if err != nil { errors = append(errors, err) - continue + return 1 } - - inst := devInfoData.DevInst - removeDeviceParams := setupapi.RemoveDeviceParams{ - ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE), - Scope: setupapi.DI_REMOVEDEVICE_GLOBAL, - } - err = devInfo.SetClassInstallParams(devInfoData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams))) - if err != nil { - errors = append(errors, err) - continue - } - err = devInfo.CallClassInstaller(setupapi.DIF_REMOVE, devInfoData) - if err != nil { - errors = append(errors, err) - continue - } - rebootRequired = rebootRequired || checkReboot(devInfo, devInfoData) - deviceInstancesDeleted = append(deviceInstancesDeleted, inst) + rebootRequired = rebootRequired || rebootRequired2 + return 1 + } + r1, _, e1 := syscall.Syscall(procWintunEnumAdapters.Addr(), 3, uintptr(unsafe.Pointer(pool)), uintptr(windows.NewCallback(cb)), 0) + if r1 == 0 { + errors = append(errors, e1) } return } -// isMember checks if SPDRP_DEVICEDESC or SPDRP_FRIENDLYNAME match device type name. -func (pool Pool) isMember(devInfo setupapi.DevInfo, devInfoData *setupapi.DevInfoData) (bool, error) { - deviceDescVal, err := devInfo.DeviceRegistryProperty(devInfoData, setupapi.SPDRP_DEVICEDESC) - if err != nil { - return false, fmt.Errorf("DeviceRegistryPropertyString(SPDRP_DEVICEDESC) failed: %v", err) - } - deviceDesc, _ := deviceDescVal.(string) - friendlyNameVal, err := devInfo.DeviceRegistryProperty(devInfoData, setupapi.SPDRP_FRIENDLYNAME) - if err != nil { - return false, fmt.Errorf("DeviceRegistryPropertyString(SPDRP_FRIENDLYNAME) failed: %v", err) +// Name returns the name of the Wintun adapter. +func (wintun *Adapter) Name() (ifname string, err error) { + var ifname16 [AdapterNameMax]uint16 + r1, _, e1 := syscall.Syscall(procWintunGetAdapterName.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&ifname16[0])), 0) + if r1 == 0 { + err = e1 + return } - friendlyName, _ := friendlyNameVal.(string) - deviceTypeName := pool.deviceTypeName() - return friendlyName == deviceTypeName || deviceDesc == deviceTypeName || - removeNumberedSuffix(friendlyName) == deviceTypeName || removeNumberedSuffix(deviceDesc) == deviceTypeName, nil + ifname = windows.UTF16ToString(ifname16[:]) + return } -// checkReboot checks device install parameters if a system reboot is required. -func checkReboot(devInfo setupapi.DevInfo, devInfoData *setupapi.DevInfoData) bool { - devInstallParams, err := devInfo.DeviceInstallParams(devInfoData) - if err != nil { - return false +// DeleteDriver deletes all Wintun adapters in a pool and if there are no more adapters in any other +// pools, also removes Wintun from the driver store, usually called by uninstallers. +func (pool *Pool) DeleteDriver() (rebootRequired bool, err error) { + var _p0 uint32 + r1, _, e1 := syscall.Syscall(procWintunDeletePoolDriver.Addr(), 2, uintptr(unsafe.Pointer(pool)), uintptr(unsafe.Pointer(&_p0)), 0) + rebootRequired = _p0 != 0 + if r1 == 0 { + err = e1 } + return - return (devInstallParams.Flags & (setupapi.DI_NEEDREBOOT | setupapi.DI_NEEDRESTART)) != 0 } -// setQuietInstall sets device install parameters for a quiet installation -func setQuietInstall(devInfo setupapi.DevInfo, devInfoData *setupapi.DevInfoData) error { - devInstallParams, err := devInfo.DeviceInstallParams(devInfoData) +// SetName sets name of the Wintun adapter. +func (wintun *Adapter) SetName(ifname string) (err error) { + ifname16, err := windows.UTF16FromString(ifname) if err != nil { return err } - - devInstallParams.Flags |= setupapi.DI_QUIETINSTALL - return devInfo.SetDeviceInstallParams(devInfoData, devInstallParams) -} - -// deviceTypeName returns pool-specific device type name. -func (pool Pool) deviceTypeName() string { - return fmt.Sprintf("%s Tunnel", pool) -} - -// Name returns the name of the Wintun interface. -func (wintun *Interface) Name() (string, error) { - return nci.ConnectionName(&wintun.cfgInstanceID) -} - -// SetName sets name of the Wintun interface. -func (wintun *Interface) SetName(ifname string) error { - const maxSuffix = 1000 - availableIfname := ifname - for i := 0; ; i++ { - err := nci.SetConnectionName(&wintun.cfgInstanceID, availableIfname) - if err == windows.ERROR_DUP_NAME { - duplicateGuid, err2 := iphlpapi.InterfaceGUIDFromAlias(availableIfname) - if err2 == nil { - for j := 0; j < maxSuffix; j++ { - proposal := fmt.Sprintf("%s %d", ifname, j+1) - if proposal == availableIfname { - continue - } - err2 = nci.SetConnectionName(duplicateGuid, proposal) - if err2 == windows.ERROR_DUP_NAME { - continue - } - if err2 == nil { - err = nci.SetConnectionName(&wintun.cfgInstanceID, availableIfname) - if err == nil { - break - } - } - break - } - } - } - if err == nil { - break - } - - if i > maxSuffix || err != windows.ERROR_DUP_NAME { - return fmt.Errorf("NciSetConnectionName failed: %v", err) - } - availableIfname = fmt.Sprintf("%s %d", ifname, i+1) - } - - // TODO: This should use NetSetup2 so that it doesn't get unset. - deviceRegKey, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.deviceRegKeyName(), registry.SET_VALUE) - if err != nil { - return fmt.Errorf("Device-level registry key open failed: %v", err) + r1, _, e1 := syscall.Syscall(procWintunSetAdapterName.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&ifname16[0])), 0) + if r1 == 0 { + err = e1 } - defer deviceRegKey.Close() - err = deviceRegKey.SetStringValue("FriendlyName", wintun.pool.deviceTypeName()) - if err != nil { - return fmt.Errorf("SetStringValue(FriendlyName) failed: %v", err) - } - return nil -} - -// tcpipAdapterRegKeyName returns the adapter-specific TCP/IP network registry key name. -func (wintun *Interface) tcpipAdapterRegKeyName() string { - return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", wintun.cfgInstanceID) -} - -// deviceRegKeyName returns the device-level registry key name. -func (wintun *Interface) deviceRegKeyName() string { - return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Enum\\%v", wintun.devInstanceID) -} - -// Version returns the version of the Wintun driver and NDIS system currently loaded. -func (wintun *Interface) Version() (driverVersion string, ndisVersion string, err error) { - key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Wintun", registry.QUERY_VALUE) - if err != nil { - return - } - defer key.Close() - driverMajor, _, err := key.GetIntegerValue("DriverMajorVersion") - if err != nil { - return - } - driverMinor, _, err := key.GetIntegerValue("DriverMinorVersion") - if err != nil { - return - } - ndisMajor, _, err := key.GetIntegerValue("NdisMajorVersion") - if err != nil { - return - } - ndisMinor, _, err := key.GetIntegerValue("NdisMinorVersion") - if err != nil { - return - } - driverVersion = fmt.Sprintf("%d.%d", driverMajor, driverMinor) - ndisVersion = fmt.Sprintf("%d.%d", ndisMajor, ndisMinor) return } -// tcpipInterfaceRegKeyName returns the interface-specific TCP/IP network registry key name. -func (wintun *Interface) tcpipInterfaceRegKeyName() (path string, err error) { - key, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.tcpipAdapterRegKeyName(), registry.QUERY_VALUE) - if err != nil { - return "", fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %v", err) - } - paths, _, err := key.GetStringsValue("IpConfig") - key.Close() - if err != nil { - return "", fmt.Errorf("Error reading IpConfig registry key: %v", err) - } - if len(paths) == 0 { - return "", errors.New("No TCP/IP interfaces found on adapter") - } - return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\%s", paths[0]), nil -} - -// devInfoData returns TUN device info list handle and interface device info -// data. The device info list handle must be closed after use. In case the -// device is not found, windows.ERROR_OBJECT_NOT_FOUND is returned. -func (wintun *Interface) devInfoData() (setupapi.DevInfo, *setupapi.DevInfoData, error) { - // Create a list of network devices. - devInfo, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "") - if err != nil { - return 0, nil, fmt.Errorf("SetupDiGetClassDevsEx(%v) failed: %v", deviceClassNetGUID, err.Error()) - } - - for index := 0; ; index++ { - devInfoData, err := devInfo.EnumDeviceInfo(index) - if err != nil { - if err == windows.ERROR_NO_MORE_ITEMS { - break - } - continue - } - - // Get interface ID. - // TODO: Store some ID in the Wintun object such that this call isn't required. - wintun2, err := makeWintun(devInfo, devInfoData, wintun.pool) - if err != nil { - continue - } - - if wintun.cfgInstanceID == wintun2.cfgInstanceID { - err = setQuietInstall(devInfo, devInfoData) - if err != nil { - devInfo.Close() - return 0, nil, fmt.Errorf("Setting quiet installation failed: %v", err) - } - return devInfo, devInfoData, nil - } +// RunningVersion returns the version of the running Wintun driver. +func RunningVersion() (version uint32, err error) { + r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0) + version = uint32(r0) + if version == 0 { + err = e1 } - - devInfo.Close() - return 0, nil, windows.ERROR_OBJECT_NOT_FOUND + return } -// handle returns a handle to the interface device object. -func (wintun *Interface) handle() (windows.Handle, error) { - interfaces, err := setupapi.CM_Get_Device_Interface_List(wintun.devInstanceID, &deviceInterfaceNetGUID, setupapi.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) - if err != nil { - return windows.InvalidHandle, fmt.Errorf("Error listing NDIS interfaces: %v", err) +// handle returns a handle to the adapter device object. Release handle with windows.CloseHandle +func (wintun *Adapter) OpenAdapterDeviceObject() (handle windows.Handle, err error) { + r0, _, e1 := syscall.Syscall(procWintunOpenAdapterDeviceObject.Addr(), 1, uintptr(wintun.handle), 0, 0) + handle = windows.Handle(r0) + if handle == windows.InvalidHandle { + err = e1 } - handle, err := windows.CreateFile(windows.StringToUTF16Ptr(interfaces[0]), windows.GENERIC_READ|windows.GENERIC_WRITE, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, nil, windows.OPEN_EXISTING, 0, 0) - if err != nil { - return windows.InvalidHandle, fmt.Errorf("Error opening NDIS device: %v", err) - } - return handle, nil -} - -// GUID returns the GUID of the interface. -func (wintun *Interface) GUID() windows.GUID { - return wintun.cfgInstanceID -} - -// LUID returns the LUID of the interface. -func (wintun *Interface) LUID() uint64 { - return ((uint64(wintun.luidIndex) & ((1 << 24) - 1)) << 24) | ((uint64(wintun.ifType) & ((1 << 16) - 1)) << 48) + return } -func isOurHardwareID(property interface{}) bool { - hwidLC := strings.ToLower(hardwareID) - - if hwids, ok := property.([]string); ok && len(hwids) > 0 { - for i := range hwids { - if strings.ToLower(hwids[i]) == hwidLC { - return true - } - } - } - if hwid, ok := property.(string); ok && strings.ToLower(hwid) == hwidLC { - return true - } - - return false +// LUID returns the LUID of the adapter. +func (wintun *Adapter) LUID() (luid uint64) { + syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0) + return } |