mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-21 20:26:36 +00:00
chore: Move private packages to internal (#1664)
This commit is contained in:
6
internal/headers/iphlpapi/const.go
Normal file
6
internal/headers/iphlpapi/const.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package iphlpapi
|
||||
|
||||
const (
|
||||
TCPTableClass uint32 = 5
|
||||
TCP6TableClass uint32 = 5
|
||||
)
|
||||
77
internal/headers/iphlpapi/iphlpapi.go
Normal file
77
internal/headers/iphlpapi/iphlpapi.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package iphlpapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
|
||||
procGetExtendedTcpTable = modiphlpapi.NewProc("GetExtendedTcpTable")
|
||||
)
|
||||
|
||||
func GetTCPConnectionStates(family uint32) (map[MIB_TCP_STATE]uint32, error) {
|
||||
var size uint32
|
||||
|
||||
stateCounts := make(map[MIB_TCP_STATE]uint32)
|
||||
rowSize := uint32(unsafe.Sizeof(MIB_TCPROW_OWNER_PID{}))
|
||||
tableClass := TCPTableClass
|
||||
|
||||
if family == windows.AF_INET6 {
|
||||
rowSize = uint32(unsafe.Sizeof(MIB_TCP6ROW_OWNER_PID{}))
|
||||
tableClass = TCP6TableClass
|
||||
}
|
||||
|
||||
ret := getExtendedTcpTable(0, &size, true, family, tableClass, 0)
|
||||
if ret != 0 && ret != uintptr(windows.ERROR_INSUFFICIENT_BUFFER) {
|
||||
return nil, fmt.Errorf("getExtendedTcpTable (size query) failed with code %d", ret)
|
||||
}
|
||||
|
||||
buf := make([]byte, size)
|
||||
|
||||
ret = getExtendedTcpTable(uintptr(unsafe.Pointer(&buf[0])), &size, true, family, tableClass, 0)
|
||||
if ret != 0 {
|
||||
return nil, fmt.Errorf("getExtendedTcpTable (data query) failed with code %d", ret)
|
||||
}
|
||||
|
||||
numEntries := *(*uint32)(unsafe.Pointer(&buf[0]))
|
||||
|
||||
for i := range numEntries {
|
||||
var state MIB_TCP_STATE
|
||||
|
||||
if family == windows.AF_INET6 {
|
||||
row := (*MIB_TCP6ROW_OWNER_PID)(unsafe.Pointer(&buf[4+i*rowSize]))
|
||||
state = row.dwState
|
||||
} else {
|
||||
row := (*MIB_TCPROW_OWNER_PID)(unsafe.Pointer(&buf[4+i*rowSize]))
|
||||
state = row.dwState
|
||||
}
|
||||
|
||||
stateCounts[state]++
|
||||
}
|
||||
|
||||
return stateCounts, nil
|
||||
}
|
||||
|
||||
func getExtendedTcpTable(pTCPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass uint32, reserved uint32) uintptr {
|
||||
ret, _, _ := procGetExtendedTcpTable.Call(
|
||||
pTCPTable,
|
||||
uintptr(unsafe.Pointer(pdwSize)),
|
||||
uintptr(boolToInt(bOrder)),
|
||||
uintptr(ulAf),
|
||||
uintptr(tableClass),
|
||||
uintptr(reserved),
|
||||
)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
76
internal/headers/iphlpapi/types.go
Normal file
76
internal/headers/iphlpapi/types.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package iphlpapi
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MIB_TCPROW_OWNER_PID structure for IPv4.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcprow_owner_pid
|
||||
type MIB_TCPROW_OWNER_PID struct {
|
||||
dwState MIB_TCP_STATE
|
||||
dwLocalAddr uint32
|
||||
dwLocalPort uint32
|
||||
dwRemoteAddr uint32
|
||||
dwRemotePort uint32
|
||||
dwOwningPid uint32
|
||||
}
|
||||
|
||||
// MIB_TCP6ROW_OWNER_PID structure for IPv6.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcp6row_owner_pid
|
||||
type MIB_TCP6ROW_OWNER_PID struct {
|
||||
ucLocalAddr [16]byte
|
||||
dwLocalScopeId uint32
|
||||
dwLocalPort uint32
|
||||
ucRemoteAddr [16]byte
|
||||
dwRemoteScopeId uint32
|
||||
dwRemotePort uint32
|
||||
dwState MIB_TCP_STATE
|
||||
dwOwningPid uint32
|
||||
}
|
||||
|
||||
type MIB_TCP_STATE uint32
|
||||
|
||||
const (
|
||||
_ MIB_TCP_STATE = iota
|
||||
TCPStateClosed
|
||||
TCPStateListening
|
||||
TCPStateSynSent
|
||||
TCPStateSynRcvd
|
||||
TCPStateEstablished
|
||||
TCPStateFinWait1
|
||||
TCPStateFinWait2
|
||||
TCPStateCloseWait
|
||||
TCPStateClosing
|
||||
TCPStateLastAck
|
||||
TCPStateTimeWait
|
||||
TCPStateDeleteTcb
|
||||
)
|
||||
|
||||
func (state MIB_TCP_STATE) String() string {
|
||||
switch state {
|
||||
case TCPStateClosed:
|
||||
return "CLOSED"
|
||||
case TCPStateListening:
|
||||
return "LISTENING"
|
||||
case TCPStateSynSent:
|
||||
return "SYN_SENT"
|
||||
case TCPStateSynRcvd:
|
||||
return "SYN_RECEIVED"
|
||||
case TCPStateEstablished:
|
||||
return "ESTABLISHED"
|
||||
case TCPStateFinWait1:
|
||||
return "FIN_WAIT1"
|
||||
case TCPStateFinWait2:
|
||||
return "FIN_WAIT2"
|
||||
case TCPStateCloseWait:
|
||||
return "CLOSE_WAIT"
|
||||
case TCPStateClosing:
|
||||
return "CLOSING"
|
||||
case TCPStateLastAck:
|
||||
return "LAST_ACK"
|
||||
case TCPStateTimeWait:
|
||||
return "TIME_WAIT"
|
||||
case TCPStateDeleteTcb:
|
||||
return "DELETE_TCB"
|
||||
default:
|
||||
return fmt.Sprintf("UNKNOWN_%d", state)
|
||||
}
|
||||
}
|
||||
62
internal/headers/kernel32/kernel32.go
Normal file
62
internal/headers/kernel32/kernel32.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package kernel32
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
procGetDynamicTimeZoneInformationSys = kernel32.NewProc("GetDynamicTimeZoneInformation")
|
||||
kernelLocalFileTimeToFileTime = kernel32.NewProc("LocalFileTimeToFileTime")
|
||||
)
|
||||
|
||||
// SYSTEMTIME contains a date and time.
|
||||
// 📑 https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
|
||||
type SYSTEMTIME struct {
|
||||
WYear uint16
|
||||
WMonth uint16
|
||||
WDayOfWeek uint16
|
||||
WDay uint16
|
||||
WHour uint16
|
||||
WMinute uint16
|
||||
WSecond uint16
|
||||
WMilliseconds uint16
|
||||
}
|
||||
|
||||
// DynamicTimezoneInformation contains the current dynamic daylight time settings.
|
||||
// 📑 https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
|
||||
type DynamicTimezoneInformation struct {
|
||||
Bias int32
|
||||
standardName [32]uint16
|
||||
StandardDate SYSTEMTIME
|
||||
StandardBias int32
|
||||
DaylightName [32]uint16
|
||||
DaylightDate SYSTEMTIME
|
||||
DaylightBias int32
|
||||
TimeZoneKeyName [128]uint16
|
||||
DynamicDaylightTimeDisabled uint8 // BOOLEAN
|
||||
}
|
||||
|
||||
// GetDynamicTimeZoneInformation retrieves the current dynamic daylight time settings.
|
||||
// 📑 https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-getdynamictimezoneinformation
|
||||
func GetDynamicTimeZoneInformation() (DynamicTimezoneInformation, error) {
|
||||
var tzi DynamicTimezoneInformation
|
||||
|
||||
r0, _, err := procGetDynamicTimeZoneInformationSys.Call(uintptr(unsafe.Pointer(&tzi)))
|
||||
if uint32(r0) == 0xffffffff {
|
||||
return tzi, err
|
||||
}
|
||||
|
||||
return tzi, nil
|
||||
}
|
||||
|
||||
func LocalFileTimeToFileTime(localFileTime, utcFileTime *windows.Filetime) uint32 {
|
||||
ret, _, _ := kernelLocalFileTimeToFileTime.Call(
|
||||
uintptr(unsafe.Pointer(localFileTime)),
|
||||
uintptr(unsafe.Pointer(utcFileTime)))
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
112
internal/headers/netapi32/netapi32.go
Normal file
112
internal/headers/netapi32/netapi32.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package netapi32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// WKSTAInfo102 is a wrapper of WKSTA_Info_102
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102
|
||||
type wKSTAInfo102 struct {
|
||||
wki102_platform_id uint32
|
||||
wki102_computername *uint16
|
||||
wki102_langroup *uint16
|
||||
wki102_ver_major uint32
|
||||
wki102_ver_minor uint32
|
||||
wki102_lanroot *uint16
|
||||
wki102_logged_on_users uint32
|
||||
}
|
||||
|
||||
// WorkstationInfo is an idiomatic wrapper of WKSTAInfo102.
|
||||
type WorkstationInfo struct {
|
||||
PlatformId uint32
|
||||
ComputerName string
|
||||
LanGroup string
|
||||
VersionMajor uint32
|
||||
VersionMinor uint32
|
||||
LanRoot string
|
||||
LoggedOnUsers uint32
|
||||
}
|
||||
|
||||
var (
|
||||
netapi32 = windows.NewLazySystemDLL("netapi32")
|
||||
procNetWkstaGetInfo = netapi32.NewProc("NetWkstaGetInfo")
|
||||
procNetApiBufferFree = netapi32.NewProc("NetApiBufferFree")
|
||||
)
|
||||
|
||||
// NetApiStatus is a map of Network Management Error Codes.
|
||||
// https://docs.microsoft.com/en-gb/windows/win32/netmgmt/network-management-error-codes?redirectedfrom=MSDN
|
||||
var NetApiStatus = map[uint32]string{
|
||||
// Success
|
||||
0: "NERR_Success",
|
||||
// This computer name is invalid.
|
||||
2351: "NERR_InvalidComputer",
|
||||
// This operation is only allowed on the primary domain controller of the domain.
|
||||
2226: "NERR_NotPrimary",
|
||||
// This operation is not allowed on this special group.
|
||||
2234: "NERR_SpeGroupOp",
|
||||
// This operation is not allowed on the last administrative account.
|
||||
2452: "NERR_LastAdmin",
|
||||
// The password parameter is invalid.
|
||||
2203: "NERR_BadPassword",
|
||||
// The password does not meet the password policy requirements.
|
||||
// Check the minimum password length, password complexity and password history requirements.
|
||||
2245: "NERR_PasswordTooShort",
|
||||
// The user name could not be found.
|
||||
2221: "NERR_UserNotFound",
|
||||
// Errors
|
||||
5: "ERROR_ACCESS_DENIED",
|
||||
8: "ERROR_NOT_ENOUGH_MEMORY",
|
||||
87: "ERROR_INVALID_PARAMETER",
|
||||
123: "ERROR_INVALID_NAME",
|
||||
124: "ERROR_INVALID_LEVEL",
|
||||
234: "ERROR_MORE_DATA",
|
||||
1219: "ERROR_SESSION_CREDENTIAL_CONFLICT",
|
||||
}
|
||||
|
||||
// NetApiBufferFree frees the memory other network management functions use internally to return information.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmapibuf/nf-lmapibuf-netapibufferfree
|
||||
func netApiBufferFree(buffer *wKSTAInfo102) {
|
||||
procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer))) //nolint:errcheck
|
||||
}
|
||||
|
||||
// NetWkstaGetInfo returns information about the configuration of a workstation.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
|
||||
func netWkstaGetInfo() (wKSTAInfo102, uint32, error) {
|
||||
var lpwi *wKSTAInfo102
|
||||
|
||||
pLevel := uintptr(102)
|
||||
|
||||
r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi)))
|
||||
defer netApiBufferFree(lpwi)
|
||||
|
||||
if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 {
|
||||
return wKSTAInfo102{}, ret, errors.New(NetApiStatus[ret])
|
||||
}
|
||||
|
||||
deref := *lpwi
|
||||
|
||||
return deref, 0, nil
|
||||
}
|
||||
|
||||
// GetWorkstationInfo is an idiomatic wrapper for netWkstaGetInfo.
|
||||
func GetWorkstationInfo() (WorkstationInfo, error) {
|
||||
info, _, err := netWkstaGetInfo()
|
||||
if err != nil {
|
||||
return WorkstationInfo{}, err
|
||||
}
|
||||
|
||||
workstationInfo := WorkstationInfo{
|
||||
PlatformId: info.wki102_platform_id,
|
||||
ComputerName: windows.UTF16PtrToString(info.wki102_computername),
|
||||
LanGroup: windows.UTF16PtrToString(info.wki102_langroup),
|
||||
VersionMajor: info.wki102_ver_major,
|
||||
VersionMinor: info.wki102_ver_minor,
|
||||
LanRoot: windows.UTF16PtrToString(info.wki102_lanroot),
|
||||
LoggedOnUsers: info.wki102_logged_on_users,
|
||||
}
|
||||
|
||||
return workstationInfo, nil
|
||||
}
|
||||
45
internal/headers/psapi/psapi.go
Normal file
45
internal/headers/psapi/psapi.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package psapi
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// PerformanceInformation is a wrapper of the PERFORMANCE_INFORMATION struct.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-performance_information
|
||||
type PerformanceInformation struct {
|
||||
cb uint32
|
||||
CommitTotal uint
|
||||
CommitLimit uint
|
||||
CommitPeak uint
|
||||
PhysicalTotal uint
|
||||
PhysicalAvailable uint
|
||||
SystemCache uint
|
||||
KernelTotal uint
|
||||
KernelPaged uint
|
||||
KernelNonpaged uint
|
||||
PageSize uint
|
||||
HandleCount uint32
|
||||
ProcessCount uint32
|
||||
ThreadCount uint32
|
||||
}
|
||||
|
||||
var (
|
||||
psapi = windows.NewLazySystemDLL("psapi.dll")
|
||||
procGetPerformanceInfo = psapi.NewProc("GetPerformanceInfo")
|
||||
)
|
||||
|
||||
// GetPerformanceInfo returns the dereferenced version of GetLPPerformanceInfo.
|
||||
func GetPerformanceInfo() (PerformanceInformation, error) {
|
||||
var lppi PerformanceInformation
|
||||
size := (uint32)(unsafe.Sizeof(lppi))
|
||||
lppi.cb = size
|
||||
r1, _, err := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&lppi)), uintptr(size))
|
||||
|
||||
if ret := *(*bool)(unsafe.Pointer(&r1)); !ret {
|
||||
return PerformanceInformation{}, err
|
||||
}
|
||||
|
||||
return lppi, nil
|
||||
}
|
||||
41
internal/headers/slc/slc.go
Normal file
41
internal/headers/slc/slc.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package slc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
slc = windows.NewLazySystemDLL("slc.dll")
|
||||
procSLIsWindowsGenuineLocal = slc.NewProc("SLIsWindowsGenuineLocal")
|
||||
)
|
||||
|
||||
// SL_GENUINE_STATE enumeration
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/slpublic/ne-slpublic-sl_genuine_state
|
||||
type SL_GENUINE_STATE uint32
|
||||
|
||||
const (
|
||||
SL_GEN_STATE_IS_GENUINE SL_GENUINE_STATE = iota
|
||||
SL_GEN_STATE_INVALID_LICENSE
|
||||
SL_GEN_STATE_TAMPERED
|
||||
SL_GEN_STATE_OFFLINE
|
||||
SL_GEN_STATE_LAST
|
||||
)
|
||||
|
||||
// SLIsWindowsGenuineLocal function wrapper.
|
||||
func SLIsWindowsGenuineLocal() (SL_GENUINE_STATE, error) {
|
||||
var genuineState SL_GENUINE_STATE
|
||||
|
||||
_, _, err := procSLIsWindowsGenuineLocal.Call(
|
||||
uintptr(unsafe.Pointer(&genuineState)),
|
||||
)
|
||||
|
||||
if !errors.Is(err, windows.NTE_OP_OK) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return genuineState, nil
|
||||
}
|
||||
170
internal/headers/sysinfoapi/sysinfoapi.go
Normal file
170
internal/headers/sysinfoapi/sysinfoapi.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package sysinfoapi
|
||||
|
||||
import (
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// MemoryStatusEx is a wrapper for MEMORYSTATUSEX
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
|
||||
type memoryStatusEx struct {
|
||||
dwLength uint32
|
||||
DwMemoryLoad uint32
|
||||
UllTotalPhys uint64
|
||||
UllAvailPhys uint64
|
||||
UllTotalPageFile uint64
|
||||
UllAvailPageFile uint64
|
||||
UllTotalVirtual uint64
|
||||
UllAvailVirtual uint64
|
||||
UllAvailExtendedVirtual uint64
|
||||
}
|
||||
|
||||
// MemoryStatus is an idiomatic wrapper for MemoryStatusEx.
|
||||
type MemoryStatus struct {
|
||||
MemoryLoad uint32
|
||||
TotalPhys uint64
|
||||
AvailPhys uint64
|
||||
TotalPageFile uint64
|
||||
AvailPageFile uint64
|
||||
TotalVirtual uint64
|
||||
AvailVirtual uint64
|
||||
AvailExtendedVirtual uint64
|
||||
}
|
||||
|
||||
// wProcessorArchitecture is a wrapper for the union found in LP_SYSTEM_INFO
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
|
||||
type wProcessorArchitecture struct {
|
||||
WProcessorArchitecture uint16
|
||||
WReserved uint16
|
||||
}
|
||||
|
||||
// ProcessorArchitecture is an idiomatic wrapper for wProcessorArchitecture.
|
||||
type ProcessorArchitecture uint16
|
||||
|
||||
// Idiomatic values for wProcessorArchitecture.
|
||||
const (
|
||||
AMD64 ProcessorArchitecture = 9
|
||||
ARM ProcessorArchitecture = 5
|
||||
ARM64 ProcessorArchitecture = 12
|
||||
IA64 ProcessorArchitecture = 6
|
||||
INTEL ProcessorArchitecture = 0
|
||||
UNKNOWN ProcessorArchitecture = 0xffff
|
||||
)
|
||||
|
||||
// LpSystemInfo is a wrapper for LPSYSTEM_INFO
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
|
||||
type lpSystemInfo struct {
|
||||
Arch wProcessorArchitecture
|
||||
DwPageSize uint32
|
||||
LpMinimumApplicationAddress uintptr
|
||||
LpMaximumApplicationAddress uintptr
|
||||
DwActiveProcessorMask uint
|
||||
DwNumberOfProcessors uint32
|
||||
DwProcessorType uint32
|
||||
DwAllocationGranularity uint32
|
||||
WProcessorLevel uint16
|
||||
WProcessorRevision uint16
|
||||
}
|
||||
|
||||
// SystemInfo is an idiomatic wrapper for LpSystemInfo.
|
||||
type SystemInfo struct {
|
||||
Arch ProcessorArchitecture
|
||||
PageSize uint32
|
||||
MinimumApplicationAddress uintptr
|
||||
MaximumApplicationAddress uintptr
|
||||
ActiveProcessorMask uint
|
||||
NumberOfProcessors uint32
|
||||
ProcessorType uint32
|
||||
AllocationGranularity uint32
|
||||
ProcessorLevel uint16
|
||||
ProcessorRevision uint16
|
||||
}
|
||||
|
||||
// WinComputerNameFormat is a wrapper for COMPUTER_NAME_FORMAT.
|
||||
type WinComputerNameFormat int
|
||||
|
||||
// Definitions for WinComputerNameFormat constants.
|
||||
const (
|
||||
ComputerNameNetBIOS WinComputerNameFormat = iota
|
||||
ComputerNameDNSHostname
|
||||
ComputerNameDNSDomain
|
||||
ComputerNameDNSFullyQualified
|
||||
ComputerNamePhysicalNetBIOS
|
||||
ComputerNamePhysicalDNSHostname
|
||||
ComputerNamePhysicalDNSDomain
|
||||
ComputerNamePhysicalDNSFullyQualified
|
||||
ComputerNameMax
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
procGetSystemInfo = kernel32.NewProc("GetSystemInfo")
|
||||
procGlobalMemoryStatusEx = kernel32.NewProc("GlobalMemoryStatusEx")
|
||||
procGetComputerNameExW = kernel32.NewProc("GetComputerNameExW")
|
||||
)
|
||||
|
||||
// GlobalMemoryStatusEx retrieves information about the system's current usage of both physical and virtual memory.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
|
||||
func GlobalMemoryStatusEx() (MemoryStatus, error) {
|
||||
var mse memoryStatusEx
|
||||
mse.dwLength = (uint32)(unsafe.Sizeof(mse))
|
||||
r1, _, err := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&mse)))
|
||||
|
||||
if ret := *(*bool)(unsafe.Pointer(&r1)); !ret {
|
||||
return MemoryStatus{}, err
|
||||
}
|
||||
|
||||
return MemoryStatus{
|
||||
MemoryLoad: mse.DwMemoryLoad,
|
||||
TotalPhys: mse.UllTotalPhys,
|
||||
AvailPhys: mse.UllAvailPhys,
|
||||
TotalPageFile: mse.UllTotalPageFile,
|
||||
AvailPageFile: mse.UllAvailPageFile,
|
||||
TotalVirtual: mse.UllTotalVirtual,
|
||||
AvailVirtual: mse.UllAvailVirtual,
|
||||
AvailExtendedVirtual: mse.UllAvailExtendedVirtual,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetSystemInfo is an idiomatic wrapper for the GetSystemInfo function from sysinfoapi
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
|
||||
func GetSystemInfo() SystemInfo {
|
||||
var info lpSystemInfo
|
||||
|
||||
procGetSystemInfo.Call(uintptr(unsafe.Pointer(&info))) //nolint:errcheck
|
||||
|
||||
return SystemInfo{
|
||||
Arch: ProcessorArchitecture(info.Arch.WProcessorArchitecture),
|
||||
PageSize: info.DwPageSize,
|
||||
MinimumApplicationAddress: info.LpMinimumApplicationAddress,
|
||||
MaximumApplicationAddress: info.LpMinimumApplicationAddress,
|
||||
ActiveProcessorMask: info.DwActiveProcessorMask,
|
||||
NumberOfProcessors: info.DwNumberOfProcessors,
|
||||
ProcessorType: info.DwProcessorType,
|
||||
AllocationGranularity: info.DwAllocationGranularity,
|
||||
ProcessorLevel: info.WProcessorLevel,
|
||||
ProcessorRevision: info.WProcessorRevision,
|
||||
}
|
||||
}
|
||||
|
||||
// GetComputerName wraps the GetComputerNameW function in a more Go-like way
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getcomputernameexw
|
||||
func GetComputerName(f WinComputerNameFormat) (string, error) {
|
||||
// 1kb buffer to accept computer name. This should be more than enough as the maximum size
|
||||
// returned is the max length of a DNS name, which this author believes is 253 characters.
|
||||
size := 1024
|
||||
|
||||
var buffer [1024]uint16
|
||||
|
||||
r1, _, err := procGetComputerNameExW.Call(uintptr(f), uintptr(unsafe.Pointer(&buffer)), uintptr(unsafe.Pointer(&size)))
|
||||
if r1 == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bytes := buffer[0:size]
|
||||
out := utf16.Decode(bytes)
|
||||
|
||||
return string(out), nil
|
||||
}
|
||||
203
internal/headers/wtsapi32/wtsapi32.go
Normal file
203
internal/headers/wtsapi32/wtsapi32.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package wtsapi32
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type WTSTypeClass int
|
||||
|
||||
// The valid values for the WTSTypeClass enumeration.
|
||||
const (
|
||||
WTSTypeProcessInfoLevel0 WTSTypeClass = iota
|
||||
WTSTypeProcessInfoLevel1
|
||||
WTSTypeSessionInfoLevel1
|
||||
)
|
||||
|
||||
type WTSConnectState uint32
|
||||
|
||||
const (
|
||||
// wtsActive A user is logged on to the WinStation. This state occurs when a user is signed in and actively connected to the device.
|
||||
wtsActive WTSConnectState = iota
|
||||
// wtsConnected The WinStation is connected to the client.
|
||||
wtsConnected
|
||||
// wtsConnectQuery The WinStation is in the process of connecting to the client.
|
||||
wtsConnectQuery
|
||||
// wtsShadow The WinStation is shadowing another WinStation.
|
||||
wtsShadow
|
||||
// wtsDisconnected The WinStation is active but the client is disconnected.
|
||||
// This state occurs when a user is signed in but not actively connected to the device, such as when the user has chosen to exit to the lock screen.
|
||||
wtsDisconnected
|
||||
// wtsIdle The WinStation is waiting for a client to connect.
|
||||
wtsIdle
|
||||
// wtsListen The WinStation is listening for a connection. A listener session waits for requests for new client connections.
|
||||
// No user is logged on a listener session. A listener session cannot be reset, shadowed, or changed to a regular client session.
|
||||
wtsListen
|
||||
// wtsReset The WinStation is being reset.
|
||||
wtsReset
|
||||
// wtsDown The WinStation is down due to an error.
|
||||
wtsDown
|
||||
// wtsInit The WinStation is initializing.
|
||||
wtsInit
|
||||
)
|
||||
|
||||
// WTSSessionInfo1w contains information about a session on a Remote Desktop Session Host (RD Session Host) server.
|
||||
// docs: https://docs.microsoft.com/en-us/windows/win32/api/wtsapi32/ns-wtsapi32-wts_session_info_1w
|
||||
type wtsSessionInfo1 struct {
|
||||
// ExecEnvID An identifier that uniquely identifies the session within the list of sessions returned by the WTSEnumerateSessionsEx function.
|
||||
ExecEnvID uint32
|
||||
// State A value of the WTSConnectState enumeration type that specifies the connection state of a Remote Desktop Services session.
|
||||
State uint32
|
||||
// SessionID A session identifier assigned by the RD Session Host server, RD Virtualization Host server, or virtual machine.
|
||||
SessionID uint32
|
||||
// pSessionName A pointer to a null-terminated string that contains the name of this session. For example, "services", "console", or "RDP-Tcp#0".
|
||||
pSessionName *uint16
|
||||
// pHostName A pointer to a null-terminated string that contains the name of the computer that the session is running on.
|
||||
// If the session is running directly on an RD Session Host server or RD Virtualization Host server, the string contains NULL.
|
||||
// If the session is running on a virtual machine, the string contains the name of the virtual machine.
|
||||
pHostName *uint16
|
||||
// pUserName A pointer to a null-terminated string that contains the name of the user who is logged on to the session.
|
||||
// If no user is logged on to the session, the string contains NULL.
|
||||
pUserName *uint16
|
||||
// pDomainName A pointer to a null-terminated string that contains the domain name of the user who is logged on to the session.
|
||||
// If no user is logged on to the session, the string contains NULL.
|
||||
pDomainName *uint16
|
||||
// pFarmName A pointer to a null-terminated string that contains the name of the farm that the virtual machine is joined to.
|
||||
// If the session is not running on a virtual machine that is joined to a farm, the string contains NULL.
|
||||
pFarmName *uint16
|
||||
}
|
||||
|
||||
type WTSSession struct {
|
||||
ExecEnvID uint32
|
||||
State WTSConnectState
|
||||
SessionID uint32
|
||||
SessionName string
|
||||
HostName string
|
||||
UserName string
|
||||
DomainName string
|
||||
FarmName string
|
||||
}
|
||||
|
||||
var (
|
||||
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
||||
|
||||
procWTSOpenServerEx = wtsapi32.NewProc("WTSOpenServerExW")
|
||||
procWTSEnumerateSessionsEx = wtsapi32.NewProc("WTSEnumerateSessionsExW")
|
||||
procWTSFreeMemoryEx = wtsapi32.NewProc("WTSFreeMemoryExW")
|
||||
procWTSCloseServer = wtsapi32.NewProc("WTSCloseServer")
|
||||
|
||||
WTSSessionStates = map[WTSConnectState]string{
|
||||
wtsActive: "active",
|
||||
wtsConnected: "connected",
|
||||
wtsConnectQuery: "connect_query",
|
||||
wtsShadow: "shadow",
|
||||
wtsDisconnected: "disconnected",
|
||||
wtsIdle: "idle",
|
||||
wtsListen: "listen",
|
||||
wtsReset: "reset",
|
||||
wtsDown: "down",
|
||||
wtsInit: "init",
|
||||
}
|
||||
)
|
||||
|
||||
func WTSOpenServer(server string) (windows.Handle, error) {
|
||||
var (
|
||||
err error
|
||||
serverName *uint16
|
||||
)
|
||||
|
||||
if server != "" {
|
||||
serverName, err = windows.UTF16PtrFromString(server)
|
||||
if err != nil {
|
||||
return windows.InvalidHandle, err
|
||||
}
|
||||
}
|
||||
|
||||
r1, _, err := procWTSOpenServerEx.Call(uintptr(unsafe.Pointer(serverName)))
|
||||
serverHandle := windows.Handle(r1)
|
||||
|
||||
if serverHandle == windows.InvalidHandle {
|
||||
return windows.InvalidHandle, err
|
||||
}
|
||||
|
||||
return serverHandle, nil
|
||||
}
|
||||
|
||||
func WTSCloseServer(server windows.Handle) error {
|
||||
r1, _, err := procWTSCloseServer.Call(uintptr(server))
|
||||
|
||||
if r1 != 1 {
|
||||
return fmt.Errorf("failed to close server: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WTSFreeMemoryEx(class WTSTypeClass, pMemory uintptr, numberOfEntries uint32) error {
|
||||
r1, _, err := procWTSFreeMemoryEx.Call(
|
||||
uintptr(class),
|
||||
pMemory,
|
||||
uintptr(numberOfEntries),
|
||||
)
|
||||
|
||||
if r1 != 1 {
|
||||
return fmt.Errorf("failed to free memory: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WTSEnumerateSessionsEx(server windows.Handle, logger *slog.Logger) ([]WTSSession, error) {
|
||||
var sessionInfoPointer uintptr
|
||||
|
||||
var count uint32
|
||||
|
||||
pLevel := uint32(1)
|
||||
r1, _, err := procWTSEnumerateSessionsEx.Call(
|
||||
uintptr(server),
|
||||
uintptr(unsafe.Pointer(&pLevel)),
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(&sessionInfoPointer)),
|
||||
uintptr(unsafe.Pointer(&count)),
|
||||
)
|
||||
|
||||
if r1 != 1 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sessionInfoPointer != 0 {
|
||||
defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) {
|
||||
err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries)
|
||||
if err != nil {
|
||||
logger.Warn("failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err))
|
||||
}
|
||||
}(WTSTypeSessionInfoLevel1, sessionInfoPointer, count)
|
||||
}
|
||||
|
||||
var sizeTest wtsSessionInfo1
|
||||
sessionSize := unsafe.Sizeof(sizeTest)
|
||||
|
||||
sessions := make([]WTSSession, 0, count)
|
||||
|
||||
for i := range count {
|
||||
curPtr := unsafe.Pointer(sessionInfoPointer + (uintptr(i) * sessionSize))
|
||||
data := (*wtsSessionInfo1)(curPtr)
|
||||
|
||||
sessionInfo := WTSSession{
|
||||
ExecEnvID: data.ExecEnvID,
|
||||
State: WTSConnectState(data.State),
|
||||
SessionID: data.SessionID,
|
||||
SessionName: windows.UTF16PtrToString(data.pSessionName),
|
||||
HostName: windows.UTF16PtrToString(data.pHostName),
|
||||
UserName: windows.UTF16PtrToString(data.pUserName),
|
||||
DomainName: windows.UTF16PtrToString(data.pDomainName),
|
||||
FarmName: windows.UTF16PtrToString(data.pFarmName),
|
||||
}
|
||||
sessions = append(sessions, sessionInfo)
|
||||
}
|
||||
|
||||
return sessions, nil
|
||||
}
|
||||
Reference in New Issue
Block a user