2019-02-07 04:18:27 +01:00
/ * SPDX - License - Identifier : MIT
*
* Copyright ( C ) 2019 WireGuard LLC . All Rights Reserved .
* /
package wintun
import (
"errors"
"fmt"
"strings"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
2019-03-04 11:58:02 +01:00
"golang.zx2c4.com/wireguard/tun/wintun/guid"
2019-05-09 10:11:15 +02:00
"golang.zx2c4.com/wireguard/tun/wintun/netshell"
registryEx "golang.zx2c4.com/wireguard/tun/wintun/registry"
2019-03-04 11:58:02 +01:00
"golang.zx2c4.com/wireguard/tun/wintun/setupapi"
2019-02-07 04:18:27 +01:00
)
2019-03-04 14:27:16 +01:00
//
// Wintun is a handle of a Wintun adapter
//
2019-03-22 15:28:33 +01:00
type Wintun struct {
CfgInstanceID windows . GUID
LUIDIndex uint32
IfType uint32
}
2019-02-07 04:18:27 +01:00
2019-03-04 14:27:16 +01:00
var deviceClassNetGUID = windows . GUID { Data1 : 0x4d36e972 , Data2 : 0xe325 , Data3 : 0x11ce , Data4 : [ 8 ] byte { 0xbf , 0xc1 , 0x08 , 0x00 , 0x2b , 0xe1 , 0x03 , 0x18 } }
2019-02-07 04:18:27 +01:00
2019-03-04 14:27:16 +01:00
const hardwareID = "Wintun"
2019-03-08 09:42:34 +01:00
const enumerator = ""
const machineName = ""
2019-05-09 10:11:15 +02:00
const waitForRegistryTimeout = time . Second * 5
2019-02-07 04:18:27 +01:00
//
2019-03-22 15:28:33 +01:00
// MakeWintun creates interface handle and populates it from device registry key
//
2019-05-09 10:11:15 +02:00
func makeWintun ( deviceInfoSet setupapi . DevInfo , deviceInfoData * setupapi . DevInfoData ) ( * Wintun , error ) {
2019-03-22 15:28:33 +01:00
// Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key.
2019-05-09 10:11:15 +02:00
key , err := deviceInfoSet . OpenDevRegKey ( deviceInfoData , setupapi . DICS_FLAG_GLOBAL , 0 , setupapi . DIREG_DRV , registry . QUERY_VALUE )
2019-03-22 15:28:33 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "Device-specific registry key open failed: %v" , err )
2019-03-22 15:28:33 +01:00
}
defer key . Close ( )
2019-03-31 10:17:11 +02:00
// Read the NetCfgInstanceId value.
2019-05-09 10:11:15 +02:00
valueStr , err := registryEx . GetStringValue ( key , "NetCfgInstanceId" )
2019-03-22 15:28:33 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "RegQueryStringValue(\"NetCfgInstanceId\") failed: %v" , err )
2019-03-22 15:28:33 +01:00
}
// Convert to windows.GUID.
ifid , err := guid . FromString ( valueStr )
if err != nil {
return nil , fmt . Errorf ( "NetCfgInstanceId registry value is not a GUID (expected: \"{...}\", provided: %q)" , valueStr )
}
// Read the NetLuidIndex value.
2019-05-09 10:11:15 +02:00
luidIdx , _ , err := key . GetIntegerValue ( "NetLuidIndex" )
2019-03-22 15:28:33 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "RegQueryValue(\"NetLuidIndex\") failed: %v" , err )
2019-03-22 15:28:33 +01:00
}
// Read the NetLuidIndex value.
2019-05-09 10:11:15 +02:00
ifType , _ , err := key . GetIntegerValue ( "*IfType" )
2019-03-22 15:28:33 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "RegQueryValue(\"*IfType\") failed: %v" , err )
2019-03-22 15:28:33 +01:00
}
return & Wintun {
CfgInstanceID : * ifid ,
LUIDIndex : uint32 ( luidIdx ) ,
IfType : uint32 ( ifType ) ,
} , nil
}
//
// GetInterface finds interface by name.
2019-02-07 04:18:27 +01:00
//
// hwndParent is a handle to the top-level window to use for any user
// interface that is related to non-device-specific actions (such as a select-
// device dialog box that uses the global class driver list). This handle is
// optional and can be 0. If a specific top-level window is not required, set
// hwndParent to 0.
//
2019-03-22 15:28:33 +01:00
// Function returns interface if found, or nil otherwise. If the interface is
// found but not Wintun-class, the function returns interface and an error.
2019-02-07 04:18:27 +01:00
//
func GetInterface ( ifname string , hwndParent uintptr ) ( * Wintun , error ) {
// Create a list of network devices.
2019-03-08 09:42:34 +01:00
devInfoList , err := setupapi . SetupDiGetClassDevsEx ( & deviceClassNetGUID , enumerator , hwndParent , setupapi . DIGCF_PRESENT , setupapi . DevInfo ( 0 ) , machineName )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "SetupDiGetClassDevsEx(%s) failed: %v" , guid . ToString ( & deviceClassNetGUID ) , err )
2019-02-07 04:18:27 +01:00
}
defer devInfoList . Close ( )
2019-02-07 19:42:59 +01:00
// 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".
2019-02-07 04:18:27 +01:00
ifname = strings . ToLower ( ifname )
for index := 0 ; ; index ++ {
2019-03-07 15:19:27 +01:00
// Get the device from the list. Should anything be wrong with this device, continue with next.
2019-02-07 04:18:27 +01:00
deviceData , err := devInfoList . EnumDeviceInfo ( index )
if err != nil {
2019-04-13 01:58:53 +02:00
if errWin , ok := err . ( syscall . Errno ) ; ok && errWin == windows . ERROR_NO_MORE_ITEMS {
2019-02-07 04:18:27 +01:00
break
}
continue
}
// Get interface ID.
2019-05-09 10:11:15 +02:00
wintun , err := makeWintun ( devInfoList , deviceData )
2019-02-07 04:18:27 +01:00
if err != nil {
continue
}
2019-05-02 23:53:15 +02:00
//TODO: is there a better way than comparing ifnames?
2019-02-07 04:18:27 +01:00
// Get interface name.
2019-05-09 10:11:15 +02:00
ifname2 , err := wintun . GetInterfaceName ( )
2019-02-07 04:18:27 +01:00
if err != nil {
continue
}
if ifname == strings . ToLower ( ifname2 ) {
2019-02-07 22:02:51 +01:00
// Interface name found. Check its driver.
const driverType = setupapi . SPDIT_COMPATDRIVER
err = devInfoList . BuildDriverInfoList ( deviceData , driverType )
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , fmt . Errorf ( "SetupDiBuildDriverInfoList failed: %v" , err )
2019-02-07 22:02:51 +01:00
}
defer devInfoList . DestroyDriverInfoList ( deviceData , driverType )
for index := 0 ; ; index ++ {
// Get a driver from the list.
driverData , err := devInfoList . EnumDriverInfo ( deviceData , driverType , index )
if err != nil {
2019-04-13 01:58:53 +02:00
if errWin , ok := err . ( syscall . Errno ) ; ok && errWin == windows . ERROR_NO_MORE_ITEMS {
2019-02-07 22:02:51 +01:00
break
}
// Something is wrong with this driver. Skip it.
continue
}
// Get driver info details.
driverDetailData , err := devInfoList . GetDriverInfoDetail ( deviceData , driverData )
if err != nil {
// Something is wrong with this driver. Skip it.
continue
}
2019-03-04 14:27:16 +01:00
if driverDetailData . IsCompatible ( hardwareID ) {
2019-02-07 22:02:51 +01:00
// Matching hardware ID found.
2019-03-22 15:28:33 +01:00
return wintun , nil
2019-02-07 22:02:51 +01:00
}
}
// This interface is not using Wintun driver.
2019-03-31 10:17:11 +02:00
return nil , errors . New ( "Foreign network interface with the same name exists" )
2019-02-07 04:18:27 +01:00
}
}
return nil , nil
}
//
// CreateInterface creates a TUN interface.
//
// description is a string that supplies the text description of the device.
// description is optional and can be "".
//
// hwndParent is a handle to the top-level window to use for any user
// interface that is related to non-device-specific actions (such as a select-
// device dialog box that uses the global class driver list). This handle is
// optional and can be 0. If a specific top-level window is not required, set
// hwndParent to 0.
//
// Function returns the network interface ID and a flag if reboot is required.
//
func CreateInterface ( description string , hwndParent uintptr ) ( * Wintun , bool , error ) {
// Create an empty device info set for network adapter device class.
2019-03-08 09:42:34 +01:00
devInfoList , err := setupapi . SetupDiCreateDeviceInfoListEx ( & deviceClassNetGUID , hwndParent , machineName )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiCreateDeviceInfoListEx(%s) failed: %v" , guid . ToString ( & deviceClassNetGUID ) , err )
2019-02-07 04:18:27 +01:00
}
// Get the device class name from GUID.
2019-03-08 09:42:34 +01:00
className , err := setupapi . SetupDiClassNameFromGuidEx ( & deviceClassNetGUID , machineName )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiClassNameFromGuidEx(%s) failed: %v" , guid . ToString ( & deviceClassNetGUID ) , err )
2019-02-07 04:18:27 +01:00
}
// Create a new device info element and add it to the device info set.
deviceData , err := devInfoList . CreateDeviceInfo ( className , & deviceClassNetGUID , description , hwndParent , setupapi . DICD_GENERATE_ID )
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiCreateDeviceInfo failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
// Set a device information element as the selected member of a device information set.
err = devInfoList . SetSelectedDevice ( deviceData )
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiSetSelectedDevice failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
// Set Plug&Play device hardware ID property.
2019-05-03 09:34:00 +02:00
err = devInfoList . SetDeviceRegistryPropertyString ( deviceData , setupapi . SPDRP_HARDWAREID , hardwareID )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiSetDeviceRegistryProperty(SPDRP_HARDWAREID) failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
// Search for the driver.
const driverType = setupapi . SPDIT_CLASSDRIVER
2019-05-10 18:01:47 +02:00
err = devInfoList . BuildDriverInfoList ( deviceData , driverType ) //TODO: This takes ~510ms
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiBuildDriverInfoList failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
defer devInfoList . DestroyDriverInfoList ( deviceData , driverType )
driverDate := windows . Filetime { }
driverVersion := uint64 ( 0 )
2019-05-10 18:01:47 +02:00
for index := 0 ; ; index ++ { //TODO: This loop takes ~600ms
2019-02-07 04:18:27 +01:00
// Get a driver from the list.
driverData , err := devInfoList . EnumDriverInfo ( deviceData , driverType , index )
if err != nil {
2019-04-13 01:58:53 +02:00
if errWin , ok := err . ( syscall . Errno ) ; ok && errWin == windows . ERROR_NO_MORE_ITEMS {
2019-02-07 04:18:27 +01:00
break
}
// Something is wrong with this driver. Skip it.
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 ) {
// Get driver info details.
driverDetailData , err := devInfoList . GetDriverInfoDetail ( deviceData , driverData )
if err != nil {
// Something is wrong with this driver. Skip it.
continue
}
2019-03-04 14:27:16 +01:00
if driverDetailData . IsCompatible ( hardwareID ) {
2019-02-07 04:18:27 +01:00
// Matching hardware ID found. Select the driver.
err := devInfoList . SetSelectedDriver ( deviceData , driverData )
if err != nil {
// Something is wrong with this driver. Skip it.
continue
}
driverDate = driverData . DriverDate
driverVersion = driverData . DriverVersion
}
}
}
if driverVersion == 0 {
2019-03-08 09:43:54 +01:00
return nil , false , fmt . Errorf ( "No driver for device %q installed" , hardwareID )
2019-02-07 04:18:27 +01:00
}
// Call appropriate class installer.
err = devInfoList . CallClassInstaller ( setupapi . DIF_REGISTERDEVICE , deviceData )
if err != nil {
2019-05-10 18:01:47 +02:00
return nil , false , fmt . Errorf ( "SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
2019-03-08 09:45:59 +01:00
// Register device co-installers if any. (Ignore errors)
2019-02-07 04:18:27 +01:00
devInfoList . CallClassInstaller ( setupapi . DIF_REGISTER_COINSTALLERS , deviceData )
2019-03-08 09:45:59 +01:00
// Install interfaces if any. (Ignore errors)
2019-02-07 04:18:27 +01:00
devInfoList . CallClassInstaller ( setupapi . DIF_INSTALLINTERFACES , deviceData )
// Install the device.
err = devInfoList . CallClassInstaller ( setupapi . DIF_INSTALLDEVICE , deviceData )
2019-03-08 09:45:59 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
err = fmt . Errorf ( "SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed: %v" , err )
2019-03-08 09:45:59 +01:00
}
2019-05-10 18:01:47 +02:00
var wintun * Wintun
var rebootRequired bool
var key registry . Key
2019-02-07 04:18:27 +01:00
if err == nil {
// Check if a system reboot is required. (Ignore errors)
if ret , _ := checkReboot ( devInfoList , deviceData ) ; ret {
rebootRequired = true
}
2019-05-09 10:11:15 +02:00
// DIF_INSTALLDEVICE returns almost immediately, while the device installation
// continues in the background. It might take a while, before all registry
2019-03-07 15:34:34 +01:00
// keys and values are populated.
2019-05-10 17:34:03 +02:00
const pollTimeout = time . Millisecond * 50
for i := 0 ; i < int ( waitForRegistryTimeout / pollTimeout ) ; i ++ {
if i != 0 {
time . Sleep ( pollTimeout )
}
2019-05-10 17:37:03 +02:00
key , err = devInfoList . OpenDevRegKey ( deviceData , setupapi . DICS_FLAG_GLOBAL , 0 , setupapi . DIREG_DRV , registry . QUERY_VALUE | registry . NOTIFY )
2019-05-10 17:34:03 +02:00
if err == nil {
break
}
}
2019-05-09 10:11:15 +02:00
if err == nil {
_ , err = registryEx . GetStringValueWait ( key , "NetCfgInstanceId" , waitForRegistryTimeout )
if err == nil {
_ , err = registryEx . GetIntegerValueWait ( key , "NetLuidIndex" , waitForRegistryTimeout )
2019-03-07 15:19:27 +01:00
}
2019-05-09 10:11:15 +02:00
if err == nil {
_ , err = registryEx . GetIntegerValueWait ( key , "*IfType" , waitForRegistryTimeout )
}
key . Close ( )
}
}
2019-03-07 15:19:27 +01:00
2019-05-09 10:11:15 +02:00
if err == nil {
// Get network interface.
wintun , err = makeWintun ( devInfoList , deviceData )
}
if err == nil {
// Wait for network registry key to emerge and populate.
2019-05-10 16:59:24 +02:00
key , err = registryEx . OpenKeyWait (
2019-05-09 10:11:15 +02:00
registry . LOCAL_MACHINE ,
wintun . GetNetRegKeyName ( ) ,
2019-05-10 17:37:03 +02:00
registry . QUERY_VALUE | registry . NOTIFY ,
2019-05-09 10:11:15 +02:00
waitForRegistryTimeout )
if err == nil {
_ , err = registryEx . GetStringValueWait ( key , "Name" , waitForRegistryTimeout )
key . Close ( )
2019-03-07 15:19:27 +01:00
}
2019-02-07 04:18:27 +01:00
}
2019-05-09 10:11:15 +02:00
if err == nil {
// Wait for TCP/IP adapter registry key to emerge and populate.
2019-05-10 16:59:24 +02:00
key , err = registryEx . OpenKeyWait (
2019-05-09 10:11:15 +02:00
registry . LOCAL_MACHINE ,
2019-05-10 17:37:03 +02:00
wintun . GetTcpipAdapterRegKeyName ( ) , registry . QUERY_VALUE | registry . NOTIFY ,
2019-05-09 10:11:15 +02:00
waitForRegistryTimeout )
if err == nil {
2019-05-10 18:01:47 +02:00
_ , err = registryEx . GetFirstStringValueWait ( key , "IpConfig" , waitForRegistryTimeout )
2019-05-09 10:11:15 +02:00
key . Close ( )
}
}
2019-05-10 18:01:47 +02:00
var tcpipInterfaceRegKeyName string
2019-05-09 10:11:15 +02:00
if err == nil {
2019-05-10 18:01:47 +02:00
tcpipInterfaceRegKeyName , err = wintun . GetTcpipInterfaceRegKeyName ( )
2019-05-09 10:11:15 +02:00
if err == nil {
2019-05-10 18:01:47 +02:00
// Wait for TCP/IP interface registry key to emerge.
key , err = registryEx . OpenKeyWait (
registry . LOCAL_MACHINE ,
tcpipInterfaceRegKeyName , registry . QUERY_VALUE ,
waitForRegistryTimeout )
if err == nil {
key . Close ( )
}
2019-05-09 10:11:15 +02:00
}
}
//
// All the registry keys and values we're relying on are present now.
//
if err == nil {
// Disable dead gateway detection on our interface.
2019-05-10 18:01:47 +02:00
key , err = registry . OpenKey ( registry . LOCAL_MACHINE , tcpipInterfaceRegKeyName , registry . SET_VALUE )
2019-05-09 10:11:15 +02:00
if err != nil {
2019-05-10 18:01:47 +02:00
err = fmt . Errorf ( "Error opening interface-specific TCP/IP network registry key: %v" , err )
2019-05-09 10:11:15 +02:00
}
key . SetDWordValue ( "EnableDeadGWDetect" , 0 )
key . Close ( )
}
2019-02-07 04:18:27 +01:00
if err == nil {
2019-03-07 15:34:34 +01:00
return wintun , rebootRequired , nil
2019-02-07 04:18:27 +01:00
}
// The interface failed to install, or the interface ID was unobtainable. Clean-up.
2019-02-07 23:00:52 +01:00
removeDeviceParams := setupapi . RemoveDeviceParams {
2019-02-07 22:37:14 +01:00
ClassInstallHeader : * setupapi . MakeClassInstallHeader ( setupapi . DIF_REMOVE ) ,
Scope : setupapi . DI_REMOVEDEVICE_GLOBAL ,
2019-02-07 04:18:27 +01:00
}
// Set class installer parameters for DIF_REMOVE.
if devInfoList . SetClassInstallParams ( deviceData , & removeDeviceParams . ClassInstallHeader , uint32 ( unsafe . Sizeof ( removeDeviceParams ) ) ) == nil {
// Call appropriate class installer.
if devInfoList . CallClassInstaller ( setupapi . DIF_REMOVE , deviceData ) == nil {
// Check if a system reboot is required. (Ignore errors)
if ret , _ := checkReboot ( devInfoList , deviceData ) ; ret {
rebootRequired = true
}
}
}
2019-03-08 09:45:18 +01:00
return nil , rebootRequired , err
2019-02-07 04:18:27 +01:00
}
//
// DeleteInterface deletes a TUN interface.
//
// hwndParent is a handle to the top-level window to use for any user
// interface that is related to non-device-specific actions (such as a select-
// device dialog box that uses the global class driver list). This handle is
// optional and can be 0. If a specific top-level window is not required, set
// hwndParent to 0.
//
// Function returns true if the interface was found and deleted and a flag if
// reboot is required.
//
func ( wintun * Wintun ) DeleteInterface ( hwndParent uintptr ) ( bool , bool , error ) {
// Create a list of network devices.
2019-03-08 09:42:34 +01:00
devInfoList , err := setupapi . SetupDiGetClassDevsEx ( & deviceClassNetGUID , enumerator , hwndParent , setupapi . DIGCF_PRESENT , setupapi . DevInfo ( 0 ) , machineName )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return false , false , fmt . Errorf ( "SetupDiGetClassDevsEx(%s) failed: %v" , guid . ToString ( & deviceClassNetGUID ) , err . Error ( ) )
2019-02-07 04:18:27 +01:00
}
defer devInfoList . Close ( )
// Iterate.
for index := 0 ; ; index ++ {
2019-03-07 15:19:27 +01:00
// Get the device from the list. Should anything be wrong with this device, continue with next.
2019-02-07 04:18:27 +01:00
deviceData , err := devInfoList . EnumDeviceInfo ( index )
if err != nil {
2019-04-13 01:58:53 +02:00
if errWin , ok := err . ( syscall . Errno ) ; ok && errWin == windows . ERROR_NO_MORE_ITEMS {
2019-02-07 04:18:27 +01:00
break
}
continue
}
// Get interface ID.
2019-05-02 23:53:15 +02:00
//TODO: Store some ID in the Wintun object such that this call isn't required.
2019-05-09 10:11:15 +02:00
wintun2 , err := makeWintun ( devInfoList , deviceData )
2019-02-07 04:18:27 +01:00
if err != nil {
continue
}
2019-03-22 15:28:33 +01:00
if wintun . CfgInstanceID == wintun2 . CfgInstanceID {
2019-02-07 04:18:27 +01:00
// Remove the device.
2019-02-07 23:00:52 +01:00
removeDeviceParams := setupapi . RemoveDeviceParams {
2019-02-07 22:37:14 +01:00
ClassInstallHeader : * setupapi . MakeClassInstallHeader ( setupapi . DIF_REMOVE ) ,
Scope : setupapi . DI_REMOVEDEVICE_GLOBAL ,
2019-02-07 04:18:27 +01:00
}
// Set class installer parameters for DIF_REMOVE.
err = devInfoList . SetClassInstallParams ( deviceData , & removeDeviceParams . ClassInstallHeader , uint32 ( unsafe . Sizeof ( removeDeviceParams ) ) )
if err != nil {
2019-05-10 18:01:47 +02:00
return false , false , fmt . Errorf ( "SetupDiSetClassInstallParams failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
// Call appropriate class installer.
err = devInfoList . CallClassInstaller ( setupapi . DIF_REMOVE , deviceData )
if err != nil {
2019-05-10 18:01:47 +02:00
return false , false , fmt . Errorf ( "SetupDiCallClassInstaller failed: %v" , err )
2019-02-07 04:18:27 +01:00
}
// Check if a system reboot is required. (Ignore errors)
if ret , _ := checkReboot ( devInfoList , deviceData ) ; ret {
return true , true , nil
}
return true , false , nil
}
}
return false , false , nil
}
2019-02-07 18:24:28 +01:00
//
// FlushInterface removes all properties from the interface and gives it only a very
// vanilla IPv4 and IPv6 configuration with no addresses of any sort assigned.
//
func ( wintun * Wintun ) FlushInterface ( ) error {
//TODO: implement me!
return nil
}
//
// checkReboot checks device install parameters if a system reboot is required.
//
2019-02-07 22:09:18 +01:00
func checkReboot ( deviceInfoSet setupapi . DevInfo , deviceInfoData * setupapi . DevInfoData ) ( bool , error ) {
2019-02-07 04:18:27 +01:00
devInstallParams , err := deviceInfoSet . GetDeviceInstallParams ( deviceInfoData )
if err != nil {
return false , err
}
if ( devInstallParams . Flags & ( setupapi . DI_NEEDREBOOT | setupapi . DI_NEEDRESTART ) ) != 0 {
return true , nil
}
return false , nil
}
//
// GetInterfaceName returns network interface name.
//
func ( wintun * Wintun ) GetInterfaceName ( ) ( string , error ) {
2019-05-02 23:53:15 +02:00
key , err := registry . OpenKey ( registry . LOCAL_MACHINE , wintun . GetNetRegKeyName ( ) , registry . QUERY_VALUE )
if err != nil {
2019-05-10 18:01:47 +02:00
return "" , fmt . Errorf ( "Network-specific registry key open failed: %v" , err )
2019-05-02 23:53:15 +02:00
}
defer key . Close ( )
// Get the interface name.
2019-05-09 10:11:15 +02:00
return registryEx . GetStringValue ( key , "Name" )
2019-05-02 23:53:15 +02:00
}
2019-02-07 04:18:27 +01:00
//
// SetInterfaceName sets network interface name.
//
func ( wintun * Wintun ) SetInterfaceName ( ifname string ) error {
2019-04-01 12:00:33 +02:00
// We have to tell the various runtime COM services about the new name too. We ignore the
// error because netshell isn't available on servercore.
// TODO: netsh.exe falls back to NciSetConnection in this case. If somebody complains, maybe
// we should do the same.
_ = netshell . HrRenameConnection ( & wintun . CfgInstanceID , windows . StringToUTF16Ptr ( ifname ) )
// Set the interface name. The above line should have done this too, but in case it failed, we force it.
2019-05-09 10:11:15 +02:00
key , err := registry . OpenKey ( registry . LOCAL_MACHINE , wintun . GetNetRegKeyName ( ) , registry . SET_VALUE )
if err != nil {
2019-05-10 18:01:47 +02:00
return fmt . Errorf ( "Network-specific registry key open failed: %v" , err )
2019-05-09 10:11:15 +02:00
}
defer key . Close ( )
2019-02-07 04:18:27 +01:00
return key . SetStringValue ( "Name" , ifname )
}
2019-03-04 11:58:02 +01:00
//
2019-03-07 15:34:34 +01:00
// GetNetRegKeyName returns interface-specific network registry key name.
2019-03-04 11:58:02 +01:00
//
2019-03-07 15:34:34 +01:00
func ( wintun * Wintun ) GetNetRegKeyName ( ) string {
2019-05-10 18:01:47 +02:00
return fmt . Sprintf ( "SYSTEM\\CurrentControlSet\\Control\\Network\\%s\\%s\\Connection" , guid . ToString ( & deviceClassNetGUID ) , guid . ToString ( & wintun . CfgInstanceID ) )
2019-03-04 11:58:02 +01:00
}
2019-02-07 04:18:27 +01:00
//
2019-05-09 10:11:15 +02:00
// GetTcpipAdapterRegKeyName returns adapter-specific TCP/IP network registry key name.
2019-02-07 04:18:27 +01:00
//
2019-05-09 10:11:15 +02:00
func ( wintun * Wintun ) GetTcpipAdapterRegKeyName ( ) string {
2019-05-10 18:01:47 +02:00
return fmt . Sprintf ( "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%s" , guid . ToString ( & wintun . CfgInstanceID ) )
2019-05-09 10:11:15 +02:00
}
//
// GetTcpipInterfaceRegKeyName returns interface-specific TCP/IP network registry key name.
2019-02-07 04:18:27 +01:00
//
2019-05-10 18:01:47 +02:00
func ( wintun * Wintun ) GetTcpipInterfaceRegKeyName ( ) ( path string , err error ) {
2019-05-09 10:11:15 +02:00
key , err := registry . OpenKey ( registry . LOCAL_MACHINE , wintun . GetTcpipAdapterRegKeyName ( ) , registry . QUERY_VALUE )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return "" , fmt . Errorf ( "Error opening adapter-specific TCP/IP network registry key: %v" , err )
2019-02-07 04:18:27 +01:00
}
2019-05-10 18:01:47 +02:00
paths , _ , err := key . GetStringsValue ( "IpConfig" )
key . Close ( )
2019-02-07 04:18:27 +01:00
if err != nil {
2019-05-10 18:01:47 +02:00
return "" , fmt . Errorf ( "Error reading IpConfig registry key: %v" , err )
2019-02-07 04:18:27 +01:00
}
2019-05-10 18:01:47 +02:00
if len ( paths ) == 0 {
return "" , errors . New ( "No TCP/IP interfaces found on adapter" )
}
return fmt . Sprintf ( "SYSTEM\\CurrentControlSet\\Services\\%s" , paths [ 0 ] ) , nil
2019-02-07 04:18:27 +01:00
}
2019-03-04 14:27:16 +01:00
//
// DataFileName returns Wintun device data pipe name.
//
2019-02-07 04:18:27 +01:00
func ( wintun * Wintun ) DataFileName ( ) string {
2019-03-22 15:28:33 +01:00
return fmt . Sprintf ( "\\\\.\\Global\\WINTUN%d" , wintun . LUIDIndex )
2019-02-07 18:24:28 +01:00
}