IP Helper API: ARP, Routing, and Network Statistics
Well, this article is the last in the series ("IP Helper API: Retrieving Basic Information" and "IP Helper API: Managing IP Addresses") dedicated to the IP Helper API. We have covered most of the API calls. Now, we will talk mainly about ARP, forwarding of IP requests, and network statistics.
Retrieving ARP Information
In the previous articles, we touched a bit about how to get basic Address Resolution Protocol (ARP) information. In addition, you had the following functions defined:
- CreateIpNetEntry
- SetIpNetEntry
- DeleteIpNetEntry
- FlushIpNetTable
- CreateProxyArpEntry
- DeleteProxyArpEntry
- SendARP
They are used to create, delete, or modify ARP table entries. In each case, you should provide a valid MIB_IPNETROW struct. You also can manage proxy ARP records. All these functions may be quite useful; for example, when you're developing applications for devices that do not support IP, but are using Windows CE as a front end to access the network.
Besides, the SendARP function deserves our attention. It allows you to retrieve the MAC address of the destination IP. When might you need it? The first thing rising in my head is raw sockets. You also can use this request for authentication purposes. Below, you'll find a simple example of SendARP usage:
void CNWParamsDlg::OnSendARP()
{
IPAddr dstAddr = inet_addr("10.168.242.170");
ULONG MacAddr[2];
ULONG PhyAddrLen = 6;
memset(MacAddr,0,sizeof(MacAddr));
DWORD dwRes = SendARP(dstAddr,0,MacAddr,&PhyAddrLen);
if ( dwRes == NO_ERROR )
{
m_ListBox.ResetContent();
BYTE *pAddr = (BYTE*)MacAddr;
CString sTmp, sMAC;
for (int i = 0; i < PhyAddrLen - 1; i++,pAddr++)
{
sTmp.Format(L"%02X:",*pAddr);
sMAC += sTmp;
}
if ( PhyAddrLen )
{
sTmp.Format(L"%02X",*pAddr);
sMAC += sTmp;
}
if ( !sMAC.IsEmpty() )
{
m_ListBox.AddString(sMAC);
}
}
}
Note, that SendARP send requests to local network, so all calls with outer IP will fail.
Utilizing Routing Mechanism
Let's move now to other networking issue. Most of IP requests are forwarded to their destinations. With IP Helper API, you have rich capabilities to manage the way how datagrams are routed over the network. You have the following functions to manage the IP routing table, and to obtain other routing information:
- GetIpForwardTable—to get the contents of IP forwarding table
- CreateIpForwardEntry—to create entry
- DeleteIpForwardEntry—to delete entry
- SetIpForwardEntry—to modify entry
- GetBestRoute—to get the best route to a specified destination address
Let's start from GetIpForwardTable. This function returns the contents of IP routing table. Similar to other IP Helper tables, that's an array of MIB_IPFORWARDROW structs. This struct contains different forwarding information, which describes an IP network route. We will use it in our test only few fields. For more details, see RFC 1354. So, here is code snippet:
void CNWParamsDlg::ShowForwardRows(PMIB_IPFORWARDTABLE
pIpForwardTable)
{
m_ListBox.ResetContent();
CString sTmp;
sTmp.Format(L"NumEntries: %d",pIpForwardTable->dwNumEntries);
m_ListBox.AddString(sTmp);
in_addr addr;
TCHAR szBuffer[128];
for (int i = 0; i < pIpForwardTable->dwNumEntries; i++)
{
MIB_IFROW mibRow;
memset(&mibRow,0,sizeof(mibRow));
mibRow.dwIndex = pIpForwardTable->table[i].dwForwardIfIndex;
GetIfEntry(&mibRow);
sTmp.Format(L"Idx: %lu Name: %s",
pIpForwardTable->table[i].dwForwardIfIndex,
mibRow.wszName);
m_ListBox.AddString(sTmp);
addr.S_un.S_addr = pIpForwardTable->table[i].dwForwardDest;
char *szAddr = inet_ntoa(addr);
memset(szBuffer,0,sizeof(szBuffer));
MultiByteToWideChar(CP_ACP,0,szAddr,strlen(szAddr),szBuffer,
sizeof(szBuffer));
sTmp.Format(L" Dest IP: %s", szBuffer);
m_ListBox.AddString(sTmp);
addr.S_un.S_addr = pIpForwardTable->table[i].dwForwardMask;
szAddr = inet_ntoa(addr);
memset(szBuffer,0,sizeof(szBuffer));
MultiByteToWideChar(CP_ACP,0,szAddr,strlen(szAddr),szBuffer,
sizeof(szBuffer));
sTmp.Format(L" Subnet Mask: %s", szBuffer);
m_ListBox.AddString(sTmp);
sTmp = L" Type:";
switch (pIpForwardTable->table[i].dwForwardType)
{
case MIB_IPROUTE_TYPE_OTHER:
sTmp += L" OTHER";
break;
case MIB_IPROUTE_TYPE_INVALID:
sTmp += L" INVALID";
break;
case MIB_IPROUTE_TYPE_DIRECT: // Local
sTmp += L" DIRECT";
break;
case MIB_IPROUTE_TYPE_INDIRECT: // Remote
sTmp += L" INDIRECT";
break;
}
m_ListBox.AddString(sTmp);
}
}
void CNWParamsDlg::OnGetIpForwardTable()
{
PMIB_IPFORWARDTABLE pIpForwardTable = 0;
ULONG dwSize = 0;
DWORD dwRes = GetIpForwardTable(pIpForwardTable, &dwSize, FALSE);
if ( dwRes == ERROR_INSUFFICIENT_BUFFER )
{
pIpForwardTable = (PMIB_IPFORWARDTABLE) new BYTE[dwSize];
dwRes = GetIpForwardTable(pIpForwardTable, &dwSize, FALSE);
if ( dwRes == NO_ERROR )
ShowForwardRows(pIpForwardTable);
delete pIpForwardTable;
}
}
As you can see, the test code displays correspondend the interface index and name, destination host IP, and subnet mask and route type. Once again, all details are documented in RFC 1354, so we will not touch them here. But, anyway, the information returned gives your application enough feeding to process.



Solid state disks (SSDs) made a splash in consumer technology, and now the technology has its eyes on the enterprise storage market. Download this eBook to see what SSDs can do for your infrastructure and review the pros and cons of this potentially game-changing storage technology.