mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-08 05:56:37 +00:00
232 lines
7.5 KiB
Go
232 lines
7.5 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Copyright The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//go:build windows
|
|
|
|
package dhcpsapi
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
//nolint:gochecknoglobals
|
|
var (
|
|
modDhcpServer = windows.NewLazySystemDLL("dhcpsapi.dll")
|
|
procDhcpGetSubnetInfo = modDhcpServer.NewProc("DhcpGetSubnetInfo")
|
|
procDhcpGetSuperScopeInfoV4 = modDhcpServer.NewProc("DhcpGetSuperScopeInfoV4")
|
|
procDhcpRpcFreeMemory = modDhcpServer.NewProc("DhcpRpcFreeMemory")
|
|
procDhcpV4EnumSubnetReservations = modDhcpServer.NewProc("DhcpV4EnumSubnetReservations")
|
|
procDhcpV4FailoverGetScopeStatistics = modDhcpServer.NewProc("DhcpV4FailoverGetScopeStatistics")
|
|
procDhcpGetMibInfoV5 = modDhcpServer.NewProc("DhcpGetMibInfoV5")
|
|
)
|
|
|
|
func GetDHCPV4ScopeStatistics() ([]DHCPV4Scope, error) {
|
|
var mibInfo *DHCP_MIB_INFO_V5
|
|
|
|
if err := dhcpGetMibInfoV5(&mibInfo); err != nil {
|
|
return nil, fmt.Errorf("dhcpGetMibInfoV5: %w", err)
|
|
}
|
|
|
|
defer dhcpRpcFreeMemory(unsafe.Pointer(mibInfo))
|
|
|
|
subnetScopeInfos := make(map[DHCP_IP_ADDRESS]DHCP_SUBNET_MIB_INFO_V5, mibInfo.Scopes)
|
|
subnetMIBScopeInfos := unsafe.Slice(mibInfo.ScopeInfo, mibInfo.Scopes)
|
|
|
|
for _, subnetMIBScopeInfo := range subnetMIBScopeInfos {
|
|
subnetScopeInfos[subnetMIBScopeInfo.Subnet] = subnetMIBScopeInfo
|
|
}
|
|
|
|
var superScopeTable *DHCP_SUPER_SCOPE_TABLE
|
|
|
|
if err := dhcpGetSuperScopeInfoV4(&superScopeTable); err != nil {
|
|
return nil, fmt.Errorf("dhcpGetSuperScopeInfoV4: %w", err)
|
|
} else if superScopeTable == nil {
|
|
return nil, errors.New("dhcpGetSuperScopeInfoV4 returned nil")
|
|
}
|
|
|
|
defer dhcpRpcFreeMemory(unsafe.Pointer(superScopeTable))
|
|
|
|
scopes := make([]DHCPV4Scope, 0, superScopeTable.Count)
|
|
subnets := unsafe.Slice(superScopeTable.Entries, superScopeTable.Count)
|
|
|
|
var errs []error
|
|
|
|
for _, subnet := range subnets {
|
|
if err := (func() error {
|
|
var subnetInfo *DHCP_SUBNET_INFO
|
|
err := dhcpGetSubnetInfo(subnet.SubnetAddress, &subnetInfo)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get subnet info: %w", err)
|
|
}
|
|
|
|
defer dhcpRpcFreeMemory(unsafe.Pointer(subnetInfo))
|
|
|
|
scope := DHCPV4Scope{
|
|
Name: subnetInfo.SubnetName.String(),
|
|
SuperScopeName: subnet.SuperScopeName.String(),
|
|
ScopeIPAddress: net.IPNet{IP: subnetInfo.SubnetAddress.IPv4(), Mask: subnetInfo.SubnetMask.IPv4Mask()},
|
|
SuperScopeNumber: subnet.SuperScopeNumber,
|
|
State: subnetInfo.SubnetState,
|
|
|
|
AddressesFree: -1,
|
|
AddressesFreeOnPartnerServer: -1,
|
|
AddressesFreeOnThisServer: -1,
|
|
AddressesInUse: -1,
|
|
AddressesInUseOnPartnerServer: -1,
|
|
AddressesInUseOnThisServer: -1,
|
|
PendingOffers: -1,
|
|
ReservedAddress: -1,
|
|
}
|
|
|
|
if subnetScopeInfo, ok := subnetScopeInfos[subnetInfo.SubnetAddress]; ok {
|
|
scope.AddressesInUse = float64(subnetScopeInfo.NumAddressesInUse)
|
|
scope.AddressesFree = float64(subnetScopeInfo.NumAddressesFree)
|
|
scope.PendingOffers = float64(subnetScopeInfo.NumPendingOffers)
|
|
}
|
|
|
|
subnetReservationCount, err := dhcpV4EnumSubnetReservations(subnet.SubnetAddress)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get subnet reservation count: %w", err)
|
|
} else {
|
|
scope.ReservedAddress = float64(subnetReservationCount)
|
|
}
|
|
|
|
var subnetStatistics *DHCP_FAILOVER_STATISTICS
|
|
err = dhcpV4FailoverGetScopeStatistics(subnet.SubnetAddress, &subnetStatistics)
|
|
|
|
defer dhcpRpcFreeMemory(unsafe.Pointer(subnetStatistics))
|
|
|
|
if err == nil {
|
|
scope.AddressesFree = float64(subnetStatistics.AddrFree)
|
|
scope.AddressesInUse = float64(subnetStatistics.AddrInUse)
|
|
scope.AddressesFreeOnPartnerServer = float64(subnetStatistics.PartnerAddrFree)
|
|
scope.AddressesInUseOnPartnerServer = float64(subnetStatistics.PartnerAddrInUse)
|
|
scope.AddressesFreeOnThisServer = float64(subnetStatistics.ThisAddrFree)
|
|
scope.AddressesInUseOnThisServer = float64(subnetStatistics.ThisAddrInUse)
|
|
} else if !errors.Is(err, ERROR_DHCP_FO_SCOPE_NOT_IN_RELATIONSHIP) {
|
|
return fmt.Errorf("failed to get subnet statistics: %w", err)
|
|
}
|
|
|
|
scopes = append(scopes, scope)
|
|
|
|
return nil
|
|
})(); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
return scopes, errors.Join(errs...)
|
|
}
|
|
|
|
// dhcpGetSubnetInfo https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetsubnetinfo
|
|
func dhcpGetSubnetInfo(subnetAddress DHCP_IP_ADDRESS, subnetInfo **DHCP_SUBNET_INFO) error {
|
|
ret, _, _ := procDhcpGetSubnetInfo.Call(
|
|
0,
|
|
uintptr(subnetAddress),
|
|
uintptr(unsafe.Pointer(subnetInfo)),
|
|
)
|
|
|
|
if ret != 0 {
|
|
return fmt.Errorf("dhcpGetSubnetInfo failed with code %w", windows.Errno(ret))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// dhcpV4FailoverGetScopeStatistics https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpv4failovergetscopestatistics
|
|
func dhcpV4FailoverGetScopeStatistics(scopeId DHCP_IP_ADDRESS, stats **DHCP_FAILOVER_STATISTICS) error {
|
|
ret, _, _ := procDhcpV4FailoverGetScopeStatistics.Call(
|
|
0,
|
|
uintptr(scopeId),
|
|
uintptr(unsafe.Pointer(stats)),
|
|
)
|
|
|
|
if ret != 0 {
|
|
return fmt.Errorf("dhcpV4FailoverGetScopeStatistics failed with code %w", windows.Errno(ret))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// dhcpGetSuperScopeInfoV4 https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetsuperscopeinfov4
|
|
func dhcpGetSuperScopeInfoV4(superScopeTable **DHCP_SUPER_SCOPE_TABLE) error {
|
|
ret, _, _ := procDhcpGetSuperScopeInfoV4.Call(
|
|
0,
|
|
uintptr(unsafe.Pointer(superScopeTable)),
|
|
)
|
|
|
|
if ret != 0 {
|
|
return fmt.Errorf("dhcpGetSuperScopeInfoV4 failed with code %w", windows.Errno(ret))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// dhcpGetMibInfoV5 https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetmibinfov5
|
|
func dhcpGetMibInfoV5(mibInfo **DHCP_MIB_INFO_V5) error {
|
|
ret, _, _ := procDhcpGetMibInfoV5.Call(
|
|
0,
|
|
uintptr(unsafe.Pointer(mibInfo)),
|
|
)
|
|
|
|
if ret != 0 {
|
|
return fmt.Errorf("dhcpGetMibInfoV5 failed with code %w", windows.Errno(ret))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// dhcpV4EnumSubnetReservations https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpv4enumsubnetreservations
|
|
func dhcpV4EnumSubnetReservations(subnetAddress DHCP_IP_ADDRESS) (uint32, error) {
|
|
var (
|
|
elementsRead uint32
|
|
elementsTotal uint32
|
|
elementsInfo uintptr
|
|
resumeHandle *windows.Handle
|
|
)
|
|
|
|
ret, _, _ := procDhcpV4EnumSubnetReservations.Call(
|
|
0,
|
|
uintptr(subnetAddress),
|
|
uintptr(unsafe.Pointer(&resumeHandle)),
|
|
0,
|
|
uintptr(unsafe.Pointer(&elementsInfo)),
|
|
uintptr(unsafe.Pointer(&elementsRead)),
|
|
uintptr(unsafe.Pointer(&elementsTotal)),
|
|
)
|
|
|
|
dhcpRpcFreeMemory(unsafe.Pointer(elementsInfo))
|
|
|
|
if !errors.Is(windows.Errno(ret), windows.ERROR_MORE_DATA) && !errors.Is(windows.Errno(ret), windows.ERROR_NO_MORE_ITEMS) {
|
|
return 0, fmt.Errorf("dhcpV4EnumSubnetReservations failed with code %w", windows.Errno(ret))
|
|
}
|
|
|
|
return elementsRead + elementsTotal, nil
|
|
}
|
|
|
|
func dhcpRpcFreeMemory(pointer unsafe.Pointer) {
|
|
if uintptr(pointer) == 0 {
|
|
return
|
|
}
|
|
|
|
//nolint:dogsled
|
|
_, _, _ = procDhcpRpcFreeMemory.Call(uintptr(pointer))
|
|
}
|