Is there a way to get MAC addresses using INDY

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Is there a way to get MAC addresses using INDY

Postby quintin » Fri Mar 23, 2018 11:24 pm

I need to get the MAC addresses for nodes on a LAN so that I can set up devices remotely. I'm using c++ builder and have found a way on MSDN, but I'm sure someone will want to run it on their macbook! Is there an easy way to do this using Indy10? I have run several searches through the 4100+ pages of the Indy manual but nothing has jumped out at me. Same with google.

Thanks in advance
Quintin
quintin
 
Posts: 3
Joined: Fri Mar 23, 2018 10:26 pm

Re: Is there a way to get MAC addresses using INDY

Postby rlebeau » Mon Mar 26, 2018 11:47 am

quintin wrote:I need to get the MAC addresses for nodes on a LAN so that I can set up devices remotely.


Why do you need MAC Addresses for that? Why aren't IP addresses sufficient?

quintin wrote:I ... have found a way on MSDN


What way is that exactly? SendARP() (which resolves the MAC address of a given IP address)?

quintin wrote:Is there an easy way to do this using Indy10?


Not natively, no. There is nothing in socket APIs that deal with MAC addresses.

For IPv4, you would have to drop all the way down to the ethernet layer and manually send ARP requests and receive their responses. You can't do that with Indy. However, on Windows at least, there are GetIpNetTable() and GetIpNetTable2() functions in the Win32 API to retrieve Windows' ARP table containing known IPs and MACs.

For IPv6, you might be able to use Indy's TIdIcmpClient component to implement NDP (Neighbor Discovery Protocol) via ICMPv6.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1532
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Is there a way to get MAC addresses using INDY

Postby quintin » Tue Mar 27, 2018 10:30 pm

rlebeau wrote:Why do you need MAC Addresses for that? Why aren't IP addresses sufficient?


The project is for a holiday display that will be set-up and taken down annually. The cards that I’m testing have a default IP address and must be set manually. So the only way to tell them apart is from the MAC address, and I was asked to make it as “non techie” friendly as possible.

I found GetIPNetTable() on MSDN and have a function that steps through the table that gives the current IP and corresponding MAC address:
Code: Select all
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   PMIB_IPNETTABLE pIPNetTable = NULL;
   MIB_IPNETROW netRow;
   unsigned long pdwSize = 0;
   struct in_addr addr;

   GetIpNetTable(pIPNetTable, &pdwSize, TRUE);
   pIPNetTable = new MIB_IPNETTABLE[pdwSize];
   if(pIPNetTable != NULL)   {
      GetIpNetTable(pIPNetTable, &pdwSize, TRUE);

      for(int i = 0; i < pIPNetTable->dwNumEntries; i++) {
         netRow = pIPNetTable->table[i];
         addr.S_un.S_addr = netRow.dwAddr;

         Memo1->Lines->Add(Format("IP address: %s",
                  ARRAYOFCONST((inet_ntoa(addr)))));
         Memo1->Lines->Add(Format("MAC address: %.2x - %.2x - %.2x - %.2x - %.2x - %.2x\r\n",
                  ARRAYOFCONST((netRow.bPhysAddr[0], netRow.bPhysAddr[1],
                             netRow.bPhysAddr[2], netRow.bPhysAddr[3],
                             netRow.bPhysAddr[4], netRow.bPhysAddr[5]))));
         }

   delete[] pIPNetTable;
}
}


My plan is to write a setup routine that will query the table and attempt to configure the cards as they are plugged into the network. I just wanted to make sure I hadn’t missed anything that would be more portable using INDY.

Finally I’d like to say I owe all of my networking ignorance to those of you who work on the INDY project! Although I haven’t worked on that many projects that needed INDY, I’ve been able to do it without knowing the difference between a Winsock and an argyle! So Thanks!
quintin
 
Posts: 3
Joined: Fri Mar 23, 2018 10:26 pm

Re: Is there a way to get MAC addresses using INDY

Postby rlebeau » Wed Mar 28, 2018 11:54 am

quintin wrote:The project is for a holiday display that will be set-up and taken down annually. The cards that I’m testing have a default IP address and must be set manually. So the only way to tell them apart is from the MAC address, and I was asked to make it as “non techie” friendly as possible.


That doesn't make much sense. If you have multiple cards on the same network, they need unique IP addresses. That is enough to differentiate them. I would be surprised if they didn't support obtaining an IP address automatically from a DNS server on the local network. That would make them more plug-n-play.

Are you wanting to get the MAC addresses so that you can then configure the IPs from within your software?

quintin wrote:I found GetIPNetTable() on MSDN and have a function that steps through the table that gives the current IP and corresponding MAC address


You are not not doing any error handling when calling GetIpNetTable(). And you are not allocating the IP array correctly, either. GetIpNetTable() returns the number of *bytes* needed for the array, not the number of *elements*, like you are currently treating it.

Try something more like this:

Code: Select all
#include <vector>

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    std::vector<BYTE> buffer;
    PMIB_IPNETTABLE pIPNetTable = NULL;
    DWORD dwRet, dwSize = 0;

    Memo1->Clear();

    /* optional: pre-allocate the buffer to a reasonable default size
        so you usually only have to call GetIpNetTable one time...

    buffer.resize(1024 * 15);
    pIPNetTable = (MIB_IPNETTABLE*) &buffer[0];
    dwSize = buffer.size();
    */

    dwRet = GetIpNetTable(pIPNetTable, &dwSize, TRUE);
    while (dwRet == ERROR_INSUFFICIENT_BUFFER)
    {
        buffer.resize(dwSize);
        pIPNetTable = (MIB_IPNETTABLE*) &buffer[0];
        dwRet = GetIpNetTable(pIPNetTable, &dwSize, TRUE);
    }

    if (dwRet == NO_ERROR)
    {
        struct in_addr addr;

        for(DWORD i = 0; i < pIPNetTable->dwNumEntries; ++i)
        {
            MIB_IPNETROW &netRow = pIPNetTable->table[i];
            addr.S_un.S_addr = netRow.dwAddr;

            Memo1->Lines->Add(Format("IP address: %s",
                ARRAYOFCONST((
                    inet_ntoa(addr)
                ))
            ));

            Memo1->Lines->Add(Format("MAC address: %.2x - %.2x - %.2x - %.2x - %.2x - %.2x\r\n",
                ARRAYOFCONST((
                    netRow.bPhysAddr[0], netRow.bPhysAddr[1],
                    netRow.bPhysAddr[2], netRow.bPhysAddr[3],
                    netRow.bPhysAddr[4], netRow.bPhysAddr[5]
                ))
            ));
        }
    }
    else if (dwRet == ERROR_NO_DATA)
    {
        Memo1->Lines->Add("No Data Available");
    }
    else
    {
        Memo1->Lines->Add("Error: " + SysErrorMessage(dwRet));
    }
}


quintin wrote:My plan is to write a setup routine that will query the table and attempt to configure the cards as they are plugged into the network. I just wanted to make sure I hadn’t missed anything that would be more portable using INDY.


Nope, you didn't.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1532
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Is there a way to get MAC addresses using INDY

Postby quintin » Thu Mar 29, 2018 2:19 am

rlebeau wrote:That doesn't make much sense. If you have multiple cards on the same network, they need unique IP addresses. That is enough to differentiate them. I would be surprised if they didn't support obtaining an IP address automatically from a DNS server on the local network. That would make them more plug-n-play.


Sorry, I should have explained this better. The cards are fairly basic (inexpensive) and have a default static IP address, and there is nothing in the documentation about obtaining an IP automatically. I have only tried it on 2 networks but it has shown up at its default IP in both instances. But, even if it could get an IP from the DNS server I still need the MAC address to identify the card and its location in the display.

rlebeau wrote:Are you wanting to get the MAC addresses so that you can then configure the IPs from within your software?


Yes, the software will assign an IP and set a couple of other parameters on the card based on the MAC address.

rlebeau wrote:You are not not doing any error handling when calling GetIpNetTable(). And you are not allocating the IP array correctly, either. GetIpNetTable() returns the number of *bytes* needed for the array, not the number of *elements*, like you are currently treating it.


This is my initial test code so I didn’t worry about error handling, I included it here because although it seemed to work I wasn’t confident that I was doing it right, which I was not. So thank you for correcting the code it gives me a good place to start!

Thanks again for your assistance,
Quintin
quintin
 
Posts: 3
Joined: Fri Mar 23, 2018 10:26 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 7 guests