Jump to content
Sign in to follow this  

UDF: DHCPGetClientInfo wrapper

Recommended Posts

#include <Date.au3>

; Description:      Get DHCP Client Attributes by IP Address, MAC or Name
; Parameter(s):     $sDHCP - IP Address of DHCP Server
;                   $ClientID - Client IP, MAC or Name (String or Native Format)
;                     Integer - native format for IP Address/Mask
;                     Binary  - native format for MAC Address (6 bytes)
;                   $iIDType - type of ClientID information:
;                     0 - Auto-define by value
;                     1 - Client IP address
;                     2 - Client Hardware (MAC) address
;                     3 - Client Name
;                   $iFlags - Config Flags:
;                     0x1- Output Format (0-Text, 1-Native)
; Requirement(s):   Testing
; Return Value(s):  On Success - The array of parameters with indexes
;                     0 - Client IP address
;                     1 - Client IP subnet mask
;                     2 - Client MAC address
;                     3 - Client Name
;                     4 - Client Comment
;                     5 - Client Lease Expires Time
;                   On Failure - Null, @error set to
;                     1 - Client not found on DHCP server
;                     2 - Invalid ClientID parameter
;                     3 - Operating System not supported
;                     4 - Any Runtime Error, API Error Code set to @extended
; Author(s):         amel27 (Alexander Melnichuk)
; Note(s):           Client Name is case sensitive

Func _DHCP_GetClientInfo($sDHCP, $ClientID, $iIDType=0, $iFlags=0)
    ; Create DHCP_SEARCH_INFO Structure
    Local $tSearchInfo= DllStructCreate("int SearchType;int DataLength;ptr DataPtr")
    Local $iSearchInfoPtr = DllStructGetPtr($tSearchInfo), $aSubnets[2]=[1,0], $iType=0
    Local $tBinaryData = DllStructCreate("dword SubnetIPAddress;ubyte HardwareID;ubyte MACAddress[6]")
    ; Check Client ID Parameter and Define SearchInfo Type
    If IsInt($ClientID) Then
        If $iIDType=0 Or $iIDType=1 Then $iType = 1
    ElseIf IsBinary($ClientID) Then
        If BinaryLen($ClientID)=6 And ($iIDType=0 Or $iIDType=2) Then $iType = 2
    ElseIf IsString($ClientID) Then
        If StringRegExp($ClientID, "^(\d+\.){3}\d+$") Then
            ; Get IP DWord type from String
            Local $aOctets = StringSplit($ClientID, "."), $iClientIP = 0
            For $i=1 To 4
                If BitAND($aOctets[$i], 0xFFFFFF00) Then Return SetError(2) ; ERR: Invalid Client IP Address
                $iClientIP = BitOR(BitRotate($iClientIP, 8, "D"), $aOctets[$i])
            $ClientID = $iClientIP
            If $iIDType=0 Or $iIDType=1 Then $iType = 1
        ElseIf StringRegExp($ClientID,"^(0[xX])?[[:xdigit:]]{2}((:|-)?[[:xdigit:]]{2}){5}$") Then
            $ClientID = Binary("0x"& StringRegExpReplace($ClientID,"(0[xX]|:|-)",""))
            If $iIDType=0 Or $iIDType=2 Then $iType = 2
            If $iIDType=0 Or $iIDType=3 Then $iType = 3
    If $iType =0 Then Return SetError(2)
    ; Route the filling of DHCP_SEARCH_INFO structure
    Switch $iType
        Case 1
            ; Filling DHCP_SEARCH_INFO for search by client IP address
            Local $tSearchInfo_IP = DllStructCreate("int SearchType;dword ClientIPAddress", $iSearchInfoPtr)
            DllStructSetData($tSearchInfo_IP, "SearchType", 0)
            DllStructSetData($tSearchInfo_IP, "ClientIPAddress", $ClientID)
        Case 2
            ; Filling DHCP_SEARCH_INFO for search by client MAC address
            DllStructSetData($tSearchInfo, "SearchType", 1)
            DllStructSetData($tSearchInfo, "DataLength", 11)
            DllStructSetData($tSearchInfo, "DataPtr", DllStructGetPtr($tBinaryData))
            ; Filling DHCP_BINARY_DATA
            DllStructSetData($tBinaryData, "HardwareID", 0x01)
            DllStructSetData($tBinaryData, "MACAddress", $ClientID)
            ; Get Array of DHCP Subnets
            $aSubnets = _DHCP_EnumSubnets($sDHCP, 1)
            If @error=1 Then Return SetError(1)
            If @error=2 Then Return SetError(4, @extended)
        Case 3
            ; Filling DHCP_SEARCH_INFO for search by client Name
            Local $tSearchInfo_Name = DllStructCreate("int SearchType;ptr ClientNamePtr", $iSearchInfoPtr)
            Local $tClientNameString= DllStructCreate("wchar ClientName["& StringLen($ClientID)+1 &"]")
            DllStructSetData($tSearchInfo_Name, "SearchType", 2)
            DllStructSetData($tSearchInfo_Name, "ClientNamePtr", DllStructGetPtr($tClientNameString))
            DllStructSetData($tClientNameString, "ClientName", $ClientID)
    ; Call  DhcpGetClientInfo API function
    Local $tClientInfo_Ptr = DllStructCreate("ptr"), $aRet, $aRes[6]
    For $i=1 To $aSubnets[0]
        DllStructSetData($tBinaryData, "SubnetIPAddress", $aSubnets[$i])
        $aRet = DllCall("Dhcpsapi.dll", "int", "DhcpGetClientInfo", _
            "wstr", $sDHCP, _ 
            "ptr", $iSearchInfoPtr, _
            "ptr", DllStructGetPtr($tClientInfo_Ptr) )
        If @error Then Return SetError(3, @error) ; ERR: Invalid DLL or Function Name
        If $aRet[0]<>20013 Then ExitLoop
    If $aRet[0]=20013 Then Return SetError(1, $aRet[0]) ; ERR: Client not found
    If $aRet[0] Then Return SetError(4, $aRet[0]) ; ERR: Any runtime errors
    ; DHCP_CLIENT_INFO structure
    Local $tClientInfo = DllStructCreate("dword ClientIpAddress;dword SubnetMask;int BinaryLen;ptr BinaryPtr;" & _
        "ptr ClientNamePtr;ptr ClientCommentPtr;ubyte ClientLeaseExpires[8];dword OwnerHostIPAddress;" & _
        "ptr OwnerHostNetBiosNamePtr;ptr OwnerHostNamePtr", DllStructGetData($tClientInfo_Ptr,1))
    Local $tClientBinary = DllStructCreate("ubyte BinaryData[6]", DllStructGetData($tClientInfo, "BinaryPtr"))
    ; Get IP Address
    $aRes[0] = DllStructGetData($tClientInfo, "ClientIpAddress")
    If BitAND($iFlags,1)=0 Then $aRes[0] = BitRotate(BitAND($aRes[0],0xFF000000), 8,"D") &"."& _
        BitRotate(BitAND($aRes[0],0x00FF0000),16,"D") &"."& _
        BitRotate(BitAND($aRes[0],0x0000FF00),-8,"W") &"."& BitAND($aRes[0],0x000000FF)
    ; Get IP Mask
    $aRes[1] = DllStructGetData($tClientInfo, "SubnetMask")
    If BitAND($iFlags,1)=0 Then $aRes[1]=BitRotate(BitAND($aRes[1],0xFF000000), 8,"D") &"."& _
        BitRotate(BitAND($aRes[1],0x00FF0000),16,"D") &"."& _
        BitRotate(BitAND($aRes[1],0x0000FF00),-8,"W") &"."& BitAND($aRes[1],0x000000FF)
    ; Get MAC Address
    $aRes[2] = DllStructGetData($tClientBinary, "BinaryData")
    If BitAND($iFlags,1)=0 Then $aRes[2] = String($aRes[2])
    ; Get Client Name
    Local $tClientNameString = DllStructCreate("wchar ClientName[255]", DllStructGetData($tClientInfo, "ClientNamePtr"))
    $aRes[3] = DllStructGetData($tClientNameString, "ClientName")
    ; Get Client Comment
    Local $tClientNameString = DllStructCreate("wchar ClientComment[255]", DllStructGetData($tClientInfo, "ClientCommentPtr"))
    $aRes[4] = DllStructGetData($tClientNameString, "ClientComment")
    ; Get Client Lease Expire Time
    $aRes[5] = DllStructGetData($tClientInfo, "ClientLeaseExpires")
    If BitAND($iFlags,1)=0 Then
        $aRes[5] = _Date_Time_FileTimeToLocalFileTime(DllStructGetPtr($tClientInfo, "ClientLeaseExpires"))
        $aRes[5] = _Date_Time_FileTimeToStr($aRes[5])
    ; Freeing a memory
    DllCall("Dhcpsapi.dll", "none", "DhcpRpcFreeMemory", "ptr", DllStructGetData($tClientInfo_Ptr,1))
    Return $aRes
EndFunc ;==> _DHCP_GetClientInfo

; Description:      Get List of DHCP Scopes
; Parameter(s):     $sDHCP - IP Address of DHCP Server
;                   $iFlags - Config Flags:
;                     0x1- Output Format (0-Text, 1-Native)
; Requirement(s):   Testing
; Return Value(s):  On Success - The array subnet of IP Addresses
;                     element with index 0 is count of scopes
;                   On Failure - @error set to
;                     1 - Scopes not defined, returned empty array
;                     2 - Any Runtime Error, invalid array,
;                         API Error Code set to @extended
; Author(s):         amel27 (Alexander Melnichuk)
; Note(s):           
Func _DHCP_EnumSubnets($sDHCP, $iFlags=0)
    Local $tEnumSubnetsParms = DllStructCreate("hwnd ResumeHandle;ptr EnumInfoPtr;int ElementsRead;int ElementsTotal")
    Local $aSubnets[1]=[0], $tIPArray, $tAddress, $aRet
        $aRet = DllCall("Dhcpsapi.dll", "int", "DhcpEnumSubnets", _
            "wstr", $sDHCP, _
            "ptr" , DllStructGetPtr($tEnumSubnetsParms, "ResumeHandle"), _
            "int", 100, _
            "ptr" , DllStructGetPtr($tEnumSubnetsParms, "EnumInfoPtr") , _
            "ptr" , DllStructGetPtr($tEnumSubnetsParms, "ElementsRead"), _
            "ptr" , DllStructGetPtr($tEnumSubnetsParms, "ElementsTotal") )
        If $aRet[0] Then Return SetError(2, $aRet[0]) ; ERR: Any runtime errors
        If DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr")=0 Then Return SetError(1, 0, $aSubnets) ; ERR: Not Found
        $tIPArray = DllStructCreate("int NumElements;ptr Elements", DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr"))
        ReDim $aSubnets[$aSubnets[0] + DllStructGetData($tIPArray,"NumElements") +1]
        For $i=$aSubnets[0]+1 To UBound($aSubnets)-1
            $tAddress = DllStructCreate("dword SubNetAddess", DllStructGetData($tIPArray,2) + ($i-$aSubnets[0]-1)*4)
            $aSubnets[$i]=DllStructGetData($tAddress, "SubNetAddess")
            If BitAND($iFlags,1)=0 Then $aSubnets[$i] = BitRotate(BitAND($aSubnets[$i],0xFF000000), 8,"D") _
                &"."& BitRotate(BitAND($aSubnets[$i],0x00FF0000),16,"D") _
                &"."& BitRotate(BitAND($aSubnets[$i],0x0000FF00),-8,"W") _
                &"."& BitAND($aSubnets[$i],0x000000FF)
        $aSubnets[0] += DllStructGetData($tIPArray,"NumElements")
    Until DllStructGetData($tEnumSubnetsParms,"ElementsRead") = DllStructGetData($tEnumSubnetsParms,"ElementsTotal")
    ; Freeing a memory
    DllCall("Dhcpsapi.dll", "none", "DhcpRpcFreeMemory", "ptr", DllStructGetData($tEnumSubnetsParms,"EnumInfoPtr"))
    Return $aSubnets
EndFunc ; => _DHCP_EnumSubnets

Edited by amel27

Share this post

Link to post
Share on other sites

- add new optional parameter "Type of Search Info" for strong typing

- add supported of Native data format for quick exchange with others API functions:

"Int" (aka "dword") for IP Address/Mask

"Binary" for Hardware (MAC) address

Share this post

Link to post
Share on other sites

- add returning of client Lease Expires Time Attribute;

- _DHCP_EnumSubnets() support unlimited scopes

Share this post

Link to post
Share on other sites

Thanks for sharing.

But could you please provide examples on how to call those functions?

I tried a few things, but nothing worked.

Local $ret = _DHCP_GetClientInfo("", "Computer1")
If @error Then MsgBox(0,"error & extended", @error & " " & @extended)

everything I tried errors out with @error = 4 and @extended = 5

Instead of "Computer1" I also tried an IP address, but that didn't work either.

any hint would be helpful


You can fool some of the people all of the time, and all of the people some of the time, but you can not fool all of the people all of the time. Abraham Lincoln - http://www.ae911truth.org/ - http://www.freedocumentaries.org/

Share this post

Link to post
Share on other sites

Would this NOT work if the DHCP server is on a Linux box (i.e. Autoit3 on Windows querying the DHCP server on Linux)?


Share this post

Link to post
Share on other sites


ERROR 5: "Access is denied", see System Error Codes


This UDF use Microsoft DHCP API, therefore it work only with Windows DHCP servers, this API work via RPC and requires sufficient rights on DHCP server.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...