Querying a DHCP server in C#
Asked Answered
C

3

9

I need to get the mapping of MAC to IP stored on DHCP server, either through a program running on the server itself or preferably through a program running on one of the DHCP clients.

I understand netsh utility can be used to get the dump however i have not had much success with that.

Any working examples or hint on that?

I have admin rights on DHCP server

Edit

I dont want to use arp cache as that would require me to either broadcast ping (which is not allowed on windows) or ping the all possible ip address of subnet( which takes lot of time).

I am sure that DHCP server stores the mapping of MAC to IP, how can i use that information, to map MAC to IP address?

Connelley answered 8/2, 2010 at 21:7 Comment(5)
i have posted it on serverfault, but not got any noteworthy answer, i feel this question requires knowledge of how the dhcp server was written and how can one hack into it. i m trying to solve a programming problem here. if u have issues with question, request a closure and do not negative vote, it discourages others to solve the question.Connelley
@bzlm i would appreciate if you help me find the answers rather than fault finding and down voting, if u feel answer is not a programming question, u are free to vote for closing the questions. i had to double post as both the forums have different audience and all i m looking for a programming solution to the problem which i did not find at serverfault.Connelley
@bzlm bytes.com/topic/net/answers/… now tell me if this is programming or not. i was looking for something on these lines.Connelley
@bzlm what whining you irrationally down vote questions discourages people from seeing it.Connelley
There is a related question here: #1511493Fulvous
F
5

You can use the DHCP Objects component from the Windows 2000 Resource Kit for this. Even though the component is hard to find, is made for Windows 2000, goes out of life support in July 2010 according to Microsoft and has very little documentation, it does work.

  1. Download the Resource Kit Tool named DHCP Objects from for example here if you can't find it at Microsoft. This will give you an .exe file that in turn will install the DHCP Objects component.
  2. Register the DHCPOBJS.DLL file with regsvr32 or create a COM+ Application for it. Which is applicable depends on how the COM component is going to be used on your system.
  3. Use the Type Library Importer tlbimp.exe to create a managed wrapper around DHCPOBJS.DLL now that it's registered by the system.
  4. In Visual Studio, add a reference to the managed wrapper. Its default generated name is DhcpObjects.dll.

Now you can write code like this against the component:

using DhcpObjects;
class Program {
    static void Main(string[] args) {
        var manager = new Manager();
        var server = dhcpmgr.Servers.Connect("1.2.3.4");
        // query server here
    }
}

The installer also provides a Windows Help File which contains further documentation on how to query and manipulate a DHCP server. The section "The Object Model" is quite helpful.

Fulvous answered 11/2, 2010 at 8:29 Comment(0)
E
2
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Net;

namespace dhcp
{
// c# class for processed clients

public class dhcpClient
{
    public string hostname { get; set; }
    public string ip       { get; set; }
    public string mac      { get; set; }
}

// structs for use with call to unmanaged code

[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_INFO_ARRAY
{
    public uint NumElements;
    public IntPtr Clients;
}

[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_UID
{
    public uint DataLength;
    public IntPtr Data;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_CLIENT_INFO
{
    public uint ip;
    public uint subnet;

    public DHCP_CLIENT_UID mac;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string ClientName;

    [MarshalAs(UnmanagedType.LPWStr)]
    public string ClientComment;
}

// main

class Program
{
    static void Main()
    {
        try
        {
            // get settings

            String server, subnet;

            Console.Write("Enter server : ");
            server = Console.ReadLine();
            Console.Write("Enter subnet : ");
            subnet = Console.ReadLine();

            // gather clients

            ArrayList clients = findDhcpClients(server, subnet);

            // output results

            Console.WriteLine();

            foreach (dhcpClient d in clients)
                Console.WriteLine(String.Format("{0,-35} {1,-15} {2,-15}", d.hostname, d.ip, d.mac));

            Console.WriteLine('\n' + clients.Count.ToString() + " lease(s) in total");
        }

        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        Console.ReadLine();
    }

    static ArrayList findDhcpClients(string server, string subnet)
    {
        // set up container for processed clients

        ArrayList foundClients = new ArrayList();

        // make call to unmanaged code

        uint parsedMask     = StringIPAddressToUInt32(subnet);
        uint resumeHandle   = 0;
        uint numClientsRead = 0;
        uint totalClients   = 0;

        IntPtr info_array_ptr;

        uint response = DhcpEnumSubnetClients(
            server,
            parsedMask,
            ref resumeHandle,
            65536,
            out info_array_ptr,
            ref numClientsRead,
            ref totalClients
            );

        // set up client array casted to a DHCP_CLIENT_INFO_ARRAY
        // using the pointer from the response object above

        DHCP_CLIENT_INFO_ARRAY rawClients =
            (DHCP_CLIENT_INFO_ARRAY)Marshal.PtrToStructure(info_array_ptr, typeof(DHCP_CLIENT_INFO_ARRAY));

        // loop through the clients structure inside rawClients 
        // adding to the dchpClient collection

        IntPtr current = rawClients.Clients;

        for (int i = 0; i < (int)rawClients.NumElements; i++)
        {
            // 1. Create machine object using the struct

            DHCP_CLIENT_INFO rawMachine =
                (DHCP_CLIENT_INFO)Marshal.PtrToStructure(Marshal.ReadIntPtr(current), typeof(DHCP_CLIENT_INFO));

            // 2. create new C# dhcpClient object and add to the 
            // collection (for hassle-free use elsewhere!!)

            dhcpClient thisClient = new dhcpClient();

            thisClient.ip = UInt32IPAddressToString(rawMachine.ip);

            thisClient.hostname = rawMachine.ClientName;

            thisClient.mac = String.Format("{0:x2}{1:x2}.{2:x2}{3:x2}.{4:x2}{5:x2}",
                Marshal.ReadByte(rawMachine.mac.Data),
                Marshal.ReadByte(rawMachine.mac.Data, 1),
                Marshal.ReadByte(rawMachine.mac.Data, 2),
                Marshal.ReadByte(rawMachine.mac.Data, 3),
                Marshal.ReadByte(rawMachine.mac.Data, 4),
                Marshal.ReadByte(rawMachine.mac.Data, 5));

            foundClients.Add(thisClient);

            // 3. move pointer to next machine

            current = (IntPtr)((int)current + (int)Marshal.SizeOf(typeof(IntPtr)));
        }

        return foundClients;
    }

    public static uint StringIPAddressToUInt32(string ip)
    {
        // convert string IP to uint IP e.g. "1.2.3.4" -> 16909060

        IPAddress i = System.Net.IPAddress.Parse(ip);
        byte[] ipByteArray = i.GetAddressBytes();

        uint ipUint = (uint)ipByteArray[0] << 24;
        ipUint += (uint)ipByteArray[1] << 16;
        ipUint += (uint)ipByteArray[2] << 8;
        ipUint += (uint)ipByteArray[3];

        return ipUint;
    }

    public static string UInt32IPAddressToString(uint ip)
    {
        // convert uint IP to string IP e.g. 16909060 -> "1.2.3.4"

        IPAddress i = new IPAddress(ip);
        string[] ipArray = i.ToString().Split('.');

        return ipArray[3] + "." + ipArray[2] + "." + ipArray[1] + "." + ipArray[0];
    }

    [DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern uint DhcpEnumSubnetClients(
            string ServerIpAddress,
            uint SubnetAddress,
        ref uint ResumeHandle,
            uint PreferredMaximum,
        out IntPtr ClientInfo,
        ref uint ElementsRead,
        ref uint ElementsTotal
    );
}
}
Enriquetaenriquez answered 13/10, 2010 at 10:38 Comment(3)
nbtstat -A MICROSOFT_DHCP_SERVER_IPEnriquetaenriquez
it will print all the leased IP addresssesEnriquetaenriquez
but only works with MICROSOFT DHCP server. I tried it with Linux but did not returned any resultsEnriquetaenriquez
H
0

Would using arp -a do the trick...on my machine the output I get is:

I have the mac/ip address replaced by bogus values to show the results...

C:\Documents and Settings\Tom>arp -a

Interface: 10.203.24.196 --- 0xf0007
  Internet Address      Physical Address      Type
  10.203.24.198         02-50-f3-10-14-06     dynamic

C:\Documents and Settings\Tom>

By shelling out using System.Diagnostics.Process, you can redirect the output to an input stream and read from it...

Hope this helps, Best regards, Tom.

Halpin answered 8/2, 2010 at 21:36 Comment(4)
dont want to use arp cache as that would require me to either broadcast ping (which is not allowed on windows) or ping the all possible ip address of subnet( which takes lot of time). I am sure that DHCP server stores the mapping of MAC to IP, how can i use that information, to map MAC to IP address?Connelley
@Connelley Are you running netsh on the DHCP server? Do you have sufficient administrative rights to query the server? I.e. if you use the DHCP MMC snap-in, can you see the information?Fulvous
@Kazoom: that would be run on the dhcp server itself, you could somehow create a webservice, tcp/ip sockets or something to query the information across to the client...Halpin
yes i have admin rights on dhcp server, once i get the info from dhcp server yes i can host a web serviceConnelley

© 2022 - 2024 — McMap. All rights reserved.