wintun: Wintun->Interface
This commit is contained in:
parent
7689d09336
commit
d94bae8348
@ -61,7 +61,7 @@ type rateJuggler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NativeTun struct {
|
type NativeTun struct {
|
||||||
wt *wintun.Wintun
|
wt *wintun.Interface
|
||||||
handle windows.Handle
|
handle windows.Handle
|
||||||
close bool
|
close bool
|
||||||
rings ringDescriptor
|
rings ringDescriptor
|
||||||
@ -84,20 +84,20 @@ func packetAlign(size uint32) uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// CreateTUN creates a Wintun adapter with the given name. Should a Wintun
|
// CreateTUN creates a Wintun interface with the given name. Should a Wintun
|
||||||
// adapter with the same name exist, it is reused.
|
// interface with the same name exist, it is reused.
|
||||||
//
|
//
|
||||||
func CreateTUN(ifname string) (Device, error) {
|
func CreateTUN(ifname string) (Device, error) {
|
||||||
return CreateTUNWithRequestedGUID(ifname, nil)
|
return CreateTUNWithRequestedGUID(ifname, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// CreateTUNWithRequestedGUID creates a Wintun adapter with the given name and
|
// CreateTUNWithRequestedGUID creates a Wintun interface with the given name and
|
||||||
// a requested GUID. Should a Wintun adapter with the same name exist, it is reused.
|
// a requested GUID. Should a Wintun interface with the same name exist, it is reused.
|
||||||
//
|
//
|
||||||
func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID) (Device, error) {
|
func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID) (Device, error) {
|
||||||
var err error
|
var err error
|
||||||
var wt *wintun.Wintun
|
var wt *wintun.Interface
|
||||||
|
|
||||||
// Does an interface with this name already exist?
|
// Does an interface with this name already exist?
|
||||||
wt, err = WintunPool.GetInterface(ifname)
|
wt, err = WintunPool.GetInterface(ifname)
|
||||||
@ -113,7 +113,7 @@ func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID) (Dev
|
|||||||
return nil, fmt.Errorf("Unable to create Wintun interface: %v", err)
|
return nil, fmt.Errorf("Unable to create Wintun interface: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = wt.SetInterfaceName(ifname, WintunPool)
|
err = wt.SetName(ifname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wt.DeleteInterface()
|
wt.DeleteInterface()
|
||||||
return nil, fmt.Errorf("Unable to set name of Wintun interface: %v", err)
|
return nil, fmt.Errorf("Unable to set name of Wintun interface: %v", err)
|
||||||
@ -143,7 +143,7 @@ func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID) (Dev
|
|||||||
return nil, fmt.Errorf("Error creating event: %v", err)
|
return nil, fmt.Errorf("Error creating event: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tun.handle, err = tun.wt.AdapterHandle()
|
tun.handle, err = tun.wt.Handle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.Close()
|
tun.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -159,7 +159,7 @@ func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID) (Dev
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) Name() (string, error) {
|
func (tun *NativeTun) Name() (string, error) {
|
||||||
return tun.wt.InterfaceName()
|
return tun.wt.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) File() *os.File {
|
func (tun *NativeTun) File() *os.File {
|
||||||
@ -300,7 +300,7 @@ func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
|||||||
return int(packetSize), nil
|
return int(packetSize), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LUID returns Windows adapter instance ID.
|
// LUID returns Windows interface instance ID.
|
||||||
func (tun *NativeTun) LUID() uint64 {
|
func (tun *NativeTun) LUID() uint64 {
|
||||||
return tun.wt.LUID()
|
return tun.wt.LUID()
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,7 @@ import (
|
|||||||
|
|
||||||
type Pool string
|
type Pool string
|
||||||
|
|
||||||
// Wintun is a handle of a Wintun adapter.
|
type Interface struct {
|
||||||
type Wintun struct {
|
|
||||||
cfgInstanceID windows.GUID
|
cfgInstanceID windows.GUID
|
||||||
devInstanceID string
|
devInstanceID string
|
||||||
luidIndex uint32
|
luidIndex uint32
|
||||||
@ -41,7 +40,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// makeWintun creates a Wintun interface handle and populates it from the device's registry key.
|
// makeWintun creates a Wintun interface handle and populates it from the device's registry key.
|
||||||
func makeWintun(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfoData, pool Pool) (*Wintun, error) {
|
func makeWintun(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfoData, pool Pool) (*Interface, error) {
|
||||||
// Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key.
|
// Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key.
|
||||||
key, err := deviceInfoSet.OpenDevRegKey(deviceInfoData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.QUERY_VALUE)
|
key, err := deviceInfoSet.OpenDevRegKey(deviceInfoData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.QUERY_VALUE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -78,7 +77,7 @@ func makeWintun(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfo
|
|||||||
return nil, fmt.Errorf("DeviceInstanceID failed: %v", err)
|
return nil, fmt.Errorf("DeviceInstanceID failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Wintun{
|
return &Interface{
|
||||||
cfgInstanceID: ifid,
|
cfgInstanceID: ifid,
|
||||||
devInstanceID: instanceID,
|
devInstanceID: instanceID,
|
||||||
luidIndex: uint32(luidIdx),
|
luidIndex: uint32(luidIdx),
|
||||||
@ -99,7 +98,7 @@ func removeNumberedSuffix(ifname string) string {
|
|||||||
// the interface if found, or windows.ERROR_OBJECT_NOT_FOUND otherwise. If
|
// 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,
|
// the interface is found but not a Wintun-class or a member of the pool,
|
||||||
// this function returns windows.ERROR_ALREADY_EXISTS.
|
// this function returns windows.ERROR_ALREADY_EXISTS.
|
||||||
func (pool Pool) GetInterface(ifname string) (*Wintun, error) {
|
func (pool Pool) GetInterface(ifname string) (*Interface, error) {
|
||||||
// Create a list of network devices.
|
// Create a list of network devices.
|
||||||
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,7 +128,7 @@ func (pool Pool) GetInterface(ifname string) (*Wintun, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is there a better way than comparing ifnames?
|
// TODO: is there a better way than comparing ifnames?
|
||||||
ifname2, err := wintun.InterfaceName()
|
ifname2, err := wintun.Name()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -186,7 +185,7 @@ func (pool Pool) GetInterface(ifname string) (*Wintun, error) {
|
|||||||
// called "requested" GUID because the API it uses is completely undocumented,
|
// called "requested" GUID because the API it uses is completely undocumented,
|
||||||
// and so there could be minor interesting complications with its usage. This
|
// 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.
|
// function returns the network interface ID and a flag if reboot is required.
|
||||||
func (pool Pool) CreateInterface(requestedGUID *windows.GUID) (wintun *Wintun, rebootRequired bool, err error) {
|
func (pool Pool) CreateInterface(requestedGUID *windows.GUID) (wintun *Interface, rebootRequired bool, err error) {
|
||||||
// Create an empty device info set for network adapter device class.
|
// Create an empty device info set for network adapter device class.
|
||||||
devInfoList, err := setupapi.SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, "")
|
devInfoList, err := setupapi.SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -203,7 +202,7 @@ func (pool Pool) CreateInterface(requestedGUID *windows.GUID) (wintun *Wintun, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new device info element and add it to the device info set.
|
// Create a new device info element and add it to the device info set.
|
||||||
deviceTypeName := pool.DeviceTypeName()
|
deviceTypeName := pool.deviceTypeName()
|
||||||
deviceData, err := devInfoList.CreateDeviceInfo(className, &deviceClassNetGUID, deviceTypeName, 0, setupapi.DICD_GENERATE_ID)
|
deviceData, err := devInfoList.CreateDeviceInfo(className, &deviceClassNetGUID, deviceTypeName, 0, setupapi.DICD_GENERATE_ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("SetupDiCreateDeviceInfo failed: %v", err)
|
err = fmt.Errorf("SetupDiCreateDeviceInfo failed: %v", err)
|
||||||
@ -410,7 +409,7 @@ func (pool Pool) CreateInterface(requestedGUID *windows.GUID) (wintun *Wintun, r
|
|||||||
// DeleteInterface deletes a Wintun interface. This function succeeds
|
// DeleteInterface deletes a Wintun interface. This function succeeds
|
||||||
// if the interface was not found. It returns a bool indicating whether
|
// if the interface was not found. It returns a bool indicating whether
|
||||||
// a reboot is required.
|
// a reboot is required.
|
||||||
func (wintun *Wintun) DeleteInterface() (rebootRequired bool, err error) {
|
func (wintun *Interface) DeleteInterface() (rebootRequired bool, err error) {
|
||||||
devInfoList, deviceData, err := wintun.deviceData()
|
devInfoList, deviceData, err := wintun.deviceData()
|
||||||
if err == windows.ERROR_OBJECT_NOT_FOUND {
|
if err == windows.ERROR_OBJECT_NOT_FOUND {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -444,7 +443,7 @@ func (wintun *Wintun) DeleteInterface() (rebootRequired bool, err error) {
|
|||||||
// DeleteMatchingInterfaces deletes all Wintun interfaces, which match
|
// DeleteMatchingInterfaces deletes all Wintun interfaces, which match
|
||||||
// given criteria, and returns which ones it deleted, whether a reboot
|
// given criteria, and returns which ones it deleted, whether a reboot
|
||||||
// is required after, and which errors occurred during the process.
|
// is required after, and which errors occurred during the process.
|
||||||
func (pool Pool) DeleteMatchingInterfaces(matches func(wintun *Wintun) bool) (deviceInstancesDeleted []uint32, rebootRequired bool, errors []error) {
|
func (pool Pool) DeleteMatchingInterfaces(matches func(wintun *Interface) bool) (deviceInstancesDeleted []uint32, rebootRequired bool, errors []error) {
|
||||||
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, []error{fmt.Errorf("SetupDiGetClassDevsEx(%v) failed: %v", deviceClassNetGUID, err.Error())}
|
return nil, false, []error{fmt.Errorf("SetupDiGetClassDevsEx(%v) failed: %v", deviceClassNetGUID, err.Error())}
|
||||||
@ -537,7 +536,7 @@ func (pool Pool) DeleteMatchingInterfaces(matches func(wintun *Wintun) bool) (de
|
|||||||
// ones it deleted, whether a reboot is required after, and which errors
|
// ones it deleted, whether a reboot is required after, and which errors
|
||||||
// occurred during the process.
|
// occurred during the process.
|
||||||
func (pool Pool) DeleteAllInterfaces() (deviceInstancesDeleted []uint32, rebootRequired bool, errors []error) {
|
func (pool Pool) DeleteAllInterfaces() (deviceInstancesDeleted []uint32, rebootRequired bool, errors []error) {
|
||||||
return pool.DeleteMatchingInterfaces(func(wintun *Wintun) bool {
|
return pool.DeleteMatchingInterfaces(func(wintun *Interface) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -554,7 +553,7 @@ func (pool Pool) isMember(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupa
|
|||||||
return false, fmt.Errorf("DeviceRegistryPropertyString(SPDRP_FRIENDLYNAME) failed: %v", err)
|
return false, fmt.Errorf("DeviceRegistryPropertyString(SPDRP_FRIENDLYNAME) failed: %v", err)
|
||||||
}
|
}
|
||||||
friendlyName, _ := friendlyNameVal.(string)
|
friendlyName, _ := friendlyNameVal.(string)
|
||||||
deviceTypeName := pool.DeviceTypeName()
|
deviceTypeName := pool.deviceTypeName()
|
||||||
return friendlyName == deviceTypeName || deviceDesc == deviceTypeName ||
|
return friendlyName == deviceTypeName || deviceDesc == deviceTypeName ||
|
||||||
removeNumberedSuffix(friendlyName) == deviceTypeName || removeNumberedSuffix(deviceDesc) == deviceTypeName, nil
|
removeNumberedSuffix(friendlyName) == deviceTypeName || removeNumberedSuffix(deviceDesc) == deviceTypeName, nil
|
||||||
}
|
}
|
||||||
@ -580,18 +579,18 @@ func setQuietInstall(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.De
|
|||||||
return deviceInfoSet.SetDeviceInstallParams(deviceInfoData, devInstallParams)
|
return deviceInfoSet.SetDeviceInstallParams(deviceInfoData, devInstallParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceTypeName returns pool-specific device type name.
|
// deviceTypeName returns pool-specific device type name.
|
||||||
func (pool Pool) DeviceTypeName() string {
|
func (pool Pool) deviceTypeName() string {
|
||||||
return fmt.Sprintf("%s Tunnel", pool)
|
return fmt.Sprintf("%s Tunnel", pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceName returns the name of the Wintun interface.
|
// Name returns the name of the Wintun interface.
|
||||||
func (wintun *Wintun) InterfaceName() (string, error) {
|
func (wintun *Interface) Name() (string, error) {
|
||||||
return nci.ConnectionName(&wintun.cfgInstanceID)
|
return nci.ConnectionName(&wintun.cfgInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInterfaceName sets name of the Wintun interface.
|
// SetName sets name of the Wintun interface.
|
||||||
func (wintun *Wintun) SetInterfaceName(ifname string) error {
|
func (wintun *Interface) SetName(ifname string) error {
|
||||||
const maxSuffix = 1000
|
const maxSuffix = 1000
|
||||||
availableIfname := ifname
|
availableIfname := ifname
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
@ -634,7 +633,7 @@ func (wintun *Wintun) SetInterfaceName(ifname string) error {
|
|||||||
return fmt.Errorf("Device-level registry key open failed: %v", err)
|
return fmt.Errorf("Device-level registry key open failed: %v", err)
|
||||||
}
|
}
|
||||||
defer deviceRegKey.Close()
|
defer deviceRegKey.Close()
|
||||||
err = deviceRegKey.SetStringValue("FriendlyName", wintun.pool.DeviceTypeName())
|
err = deviceRegKey.SetStringValue("FriendlyName", wintun.pool.deviceTypeName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("SetStringValue(FriendlyName) failed: %v", err)
|
return fmt.Errorf("SetStringValue(FriendlyName) failed: %v", err)
|
||||||
}
|
}
|
||||||
@ -642,17 +641,17 @@ func (wintun *Wintun) SetInterfaceName(ifname string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tcpipAdapterRegKeyName returns the adapter-specific TCP/IP network registry key name.
|
// tcpipAdapterRegKeyName returns the adapter-specific TCP/IP network registry key name.
|
||||||
func (wintun *Wintun) tcpipAdapterRegKeyName() string {
|
func (wintun *Interface) tcpipAdapterRegKeyName() string {
|
||||||
return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", wintun.cfgInstanceID)
|
return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters\\%v", wintun.cfgInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deviceRegKeyName returns the device-level registry key name
|
// deviceRegKeyName returns the device-level registry key name
|
||||||
func (wintun *Wintun) deviceRegKeyName() string {
|
func (wintun *Interface) deviceRegKeyName() string {
|
||||||
return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Enum\\%v", wintun.devInstanceID)
|
return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Enum\\%v", wintun.devInstanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcpipInterfaceRegKeyName returns the interface-specific TCP/IP network registry key name.
|
// tcpipInterfaceRegKeyName returns the interface-specific TCP/IP network registry key name.
|
||||||
func (wintun *Wintun) tcpipInterfaceRegKeyName() (path string, err error) {
|
func (wintun *Interface) tcpipInterfaceRegKeyName() (path string, err error) {
|
||||||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.tcpipAdapterRegKeyName(), registry.QUERY_VALUE)
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.tcpipAdapterRegKeyName(), registry.QUERY_VALUE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %v", err)
|
return "", fmt.Errorf("Error opening adapter-specific TCP/IP network registry key: %v", err)
|
||||||
@ -671,7 +670,7 @@ func (wintun *Wintun) tcpipInterfaceRegKeyName() (path string, err error) {
|
|||||||
// deviceData returns TUN device info list handle and interface device info
|
// deviceData returns TUN device info list handle and interface device info
|
||||||
// data. The device info list handle must be closed after use. In case the
|
// 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.
|
// device is not found, windows.ERROR_OBJECT_NOT_FOUND is returned.
|
||||||
func (wintun *Wintun) deviceData() (setupapi.DevInfo, *setupapi.DevInfoData, error) {
|
func (wintun *Interface) deviceData() (setupapi.DevInfo, *setupapi.DevInfoData, error) {
|
||||||
// Create a list of network devices.
|
// Create a list of network devices.
|
||||||
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -708,8 +707,8 @@ func (wintun *Wintun) deviceData() (setupapi.DevInfo, *setupapi.DevInfoData, err
|
|||||||
return 0, nil, windows.ERROR_OBJECT_NOT_FOUND
|
return 0, nil, windows.ERROR_OBJECT_NOT_FOUND
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdapterHandle returns a handle to the adapter device object.
|
// Handle returns a handle to the interface device object.
|
||||||
func (wintun *Wintun) AdapterHandle() (windows.Handle, error) {
|
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)
|
interfaces, err := setupapi.CM_Get_Device_Interface_List(wintun.devInstanceID, &deviceInterfaceNetGUID, setupapi.CM_GET_DEVICE_INTERFACE_LIST_PRESENT)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return windows.InvalidHandle, fmt.Errorf("Error listing NDIS interfaces: %v", err)
|
return windows.InvalidHandle, fmt.Errorf("Error listing NDIS interfaces: %v", err)
|
||||||
@ -722,11 +721,11 @@ func (wintun *Wintun) AdapterHandle() (windows.Handle, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GUID returns the GUID of the interface.
|
// GUID returns the GUID of the interface.
|
||||||
func (wintun *Wintun) GUID() windows.GUID {
|
func (wintun *Interface) GUID() windows.GUID {
|
||||||
return wintun.cfgInstanceID
|
return wintun.cfgInstanceID
|
||||||
}
|
}
|
||||||
|
|
||||||
// LUID returns the LUID of the interface.
|
// LUID returns the LUID of the interface.
|
||||||
func (wintun *Wintun) LUID() uint64 {
|
func (wintun *Interface) LUID() uint64 {
|
||||||
return ((uint64(wintun.luidIndex) & ((1 << 24) - 1)) << 24) | ((uint64(wintun.ifType) & ((1 << 16) - 1)) << 48)
|
return ((uint64(wintun.luidIndex) & ((1 << 24) - 1)) << 24) | ((uint64(wintun.ifType) & ((1 << 16) - 1)) << 48)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user