Click here to Skip to main content
15,311,151 members
Articles / Desktop Programming / MFC
Posted 27 Dec 2007


42 bookmarked

Edit (Add/Remove/Modify) ARP Tables

Rate me:
Please Sign up or sign in to vote.
4.91/5 (10 votes)
18 Jan 2008CPOL4 min read
A tool to display and modify IP-to-Physical address translation tables used by the Address Resolution Protocol (ARP).

Screenshot - ARPTable


This is a tool to display and modify IP-to-Physical address translation tables used by ARP (Address Resolution Protocol), like the Windows command-line arp.exe. This tool will do two things: it displays ARP table entries and it adds/modifies/removes ARP entries. These are done by requesting the SNMP (Simple Network Management Protocol) extension library.

Access IP and MAC addresses through SNMP

You can read and modify ARP tables through SNMP, by requesting SNMP to get/set object information. SNMP requests and responses through MIB (Management Information Base). MIB is like a tree, and has all the manageable objects we will use. For more information, check the RFC1213. Also check the files at %SystemRoot%\system32\*.mib. The file that has entries we will use is %SystemRoot%\system32\mib_ii.mib. You can open and see it using Notepad.

Here is an MIB ipNetToMediaEntry entry:

ipNetToMediaEntry OBJECT-TYPE
              SYNTAX  IpNetToMediaEntry
              ACCESS  not-accessible
              STATUS  mandatory
                      "Each entry contains one IpAddress to 'physical'
                      address equivalence."
              INDEX   { ipNetToMediaIfIndex,
                        ipNetToMediaNetAddress }
              ::= { ipNetToMediaTable 1 }

MIB accesses objects by the OID (Object Identifier) number. Every object has a number, and child objects have the both parent object number and their own number. The numbers are separated by a dot ".". For example, if the parent object has the number "1" and the child object has the number "3", then the child object OID number will be "1.3", and a child of the child may be "1.3.6", … "", and so on.

Here is a simple sketch of the objects tree:

Screenshot - OID ipNetToMediaEntry

Initialize the class

I used the function SnmpExtensionQuery to resolve the SNMP requests, but before using it, you must call the SnmpExtensionInit function to initialize the SNMP extension agent DLL. The two functions exist in the Microsoft library inetmib1.dll, so at the class construction, I load this library and get the addresses of these functions, and then call SnmpExtensionInit to initialize the SNMP extension agent DLL.

Here is the construction of the CARP class:

// Construction/Destruction

    // Load dynamic library: inetmib1.dll
    hMIBLibrary    = LoadLibrary(TEXT("inetmib1.dll"));

    // If library loaded, get addresses of (SnmpExtensionInit,
    // pfnSnmpExtensionQuery) functions
    if (hMIBLibrary)
        pfnSnmpExtensionInit    = (PFNSNMPEXTENSIONINIT)  GetProcAddress(hMIBLibrary, 
        pfnSnmpExtensionQuery   = (PFNSNMPEXTENSIONQUERY) GetProcAddress(hMIBLibrary, 

        // If success get addresses and initialize SNMP, bInitialized = true
        if (pfnSnmpExtensionInit && pfnSnmpExtensionQuery)
            HANDLE              hPollForTrapEvent;
            AsnObjectIdentifier aoiSupportedView;

            bInitialized        = pfnSnmpExtensionInit(0, &hPollForTrapEvent, 
        // If fail to get addresses, bInitialized = false
        bInitialized            = FALSE;
        AfxMessageBox(_T("Load library fail"));

Get ARP entries

The function GetEntries gets the ARP entries like arp.exe -a. It takes three parameters: pTable, the pointer to an array of arpTable structs that will be filled by the IP and MAC addresses; TableLength, the length of the array; AdapterIndex, the NIC adapter index number. I've used three OIDs to get the ARP table entries. OID[0] = "" to get the interface index of the entry and compare it with the AdapterIndex parameter; OID[1] = "" to get the IP and MAC addresses; OID[2] = "" to get the entry type (static or dynamic).

// Function:          GetEntries: Read ARP table for specific NIC interface.
// Parameters:
//    pTable          Pointer to array of arpTable struct
//    TableLength     Length of the array
//    AdapterIndex    NIC Adapter index number
// Returns:
//                    Number of read ARP entries
int CARP::GetEntries(arpTable* pTable, int TableLength, int AdapterIndex)
    // Be sure initialize SNMP true
    if (!bInitialized)
        return 0;

    SnmpVarBindList        SVBList[3];
    SnmpVarBind            SVBVars[3];
    UINT                   OID[3][10];
    AsnInteger32           aiErrorStatus[3], aiErrorIndex[3];
    AsnObjectIdentifier    AsnOID0 = {sizeof(OID[0])/sizeof(UINT), OID[0]};
    AsnObjectIdentifier    AsnOID1 = {sizeof(OID[1])/sizeof(UINT), OID[1]};
    AsnObjectIdentifier    AsnOID2 = {sizeof(OID[2])/sizeof(UINT), OID[2]};
    unsigned long          pIPAddress;
    unsigned long          pMACAddress;
    int                    iEntries;

    //    Fill array of 3 OIDs
    //    OID[0]    : "", ipNetToMediaIfIndex
    //                The interface on which this entry's equivalence is effective
    //    OID[1]    : "", ipNetToMediaPhysAddress
    //                The media-dependent 'physical' address
    //    OID[2]    : "", ipNetToMediaType
    //                Entry type: 1:Other, 2:Invalid(Remove), 3:Dynamic, 4:Static
    for (int count=0; count<3; count++)
        OID[count][0]        = 1;
        OID[count][1]        = 3;
        OID[count][2]        = 6;
        OID[count][3]        = 1;
        OID[count][4]        = 2;
        OID[count][5]        = 1;
        OID[count][6]        = 4;
        OID[count][7]        = 22;
        OID[count][8]        = 1;

        case 0:
            // Adapter interface
            OID[count][9]    = 1;

        case 1:
            // MAC address
            OID[count][9]    = 2;

        case 2:
            // Entry Type
            OID[count][9]    = 4;

    ZeroMemory(pTable, sizeof(arpTable)*TableLength);

    SVBList[0].len  = 1;
    SVBList[0].list = &SVBVars[0];
    SnmpUtilOidCpy(&SVBVars[0].name, &AsnOID0);

    SVBList[1].len  = 1;
    SVBList[1].list = &SVBVars[1];
    SnmpUtilOidCpy(&SVBVars[1].name, &AsnOID1);

    SVBList[2].len  = 1;
    SVBList[2].list = &SVBVars[2];
    SnmpUtilOidCpy(&SVBVars[2].name, &AsnOID2);

    iEntries        = 0;
        aiErrorStatus[0]    = 0;
        aiErrorIndex[0]     = 0;
        aiErrorStatus[1]    = 0;
        aiErrorIndex[1]     = 0;
        aiErrorStatus[2]    = 0;
        aiErrorIndex[2]     = 0;

        // Query information of 3 OIDs
        if (pfnSnmpExtensionQuery(SNMP_PDU_GETNEXT, &SVBList[0], 
                                  &aiErrorStatus[0], &aiErrorIndex[0]))
            if (pfnSnmpExtensionQuery(SNMP_PDU_GETNEXT, &SVBList[1], 
                                      &aiErrorStatus[1], &aiErrorIndex[1]))
                if (pfnSnmpExtensionQuery(SNMP_PDU_GETNEXT, &SVBList[2], 
                                          &aiErrorStatus[2], &aiErrorIndex[2]))
                    if (aiErrorStatus[0] == SNMP_ERRORSTATUS_NOERROR &&
                        aiErrorStatus[1] == SNMP_ERRORSTATUS_NOERROR &&
                        aiErrorStatus[2] == SNMP_ERRORSTATUS_NOERROR)
                        // Check for error
                        // From MSDN Help:
                        // If the extension agent cannot resolve
                        // the variable bindings on a Get Next request, 
                        // it must change the name field of the SnmpVarBind
                        // structure to the value of the object 
                        // identifier immediately following that
                        // of the currently supported MIB subtree view. 
                        // For example, if the extension agent supports
                        // view ".", a Get Next 
                        // request on "."
                        // would result in a modified name
                        // field of ".". 
                        // This signals the SNMP service to continue
                        // the attempt to resolve the variable
                        // bindings with other extension agents

                                &AsnOID0, AsnOID0.idLength)) 
                                &AsnOID1, AsnOID1.idLength)) 
                                &AsnOID2, AsnOID2.idLength)) 

                        // Verify selected Adapter interface
                        if (AdapterIndex == SVBList[0].list->value.asnValue.number)
                            // pIPAddress get pointer ro IP Address
                            pIPAddress        = (unsigned long)SVBList[1].list->name.ids;
                            pTable[iEntries].IPAddress[0] = 
                                   *(unsigned char *)(pIPAddress + 44);
                            pTable[iEntries].IPAddress[1] = 
                                   *(unsigned char *)(pIPAddress + 48);
                            pTable[iEntries].IPAddress[2] = 
                                   *(unsigned char *)(pIPAddress + 52);
                            pTable[iEntries].IPAddress[3] = 
                                   *(unsigned char *)(pIPAddress + 56);

                            // pIPAddress get pointer ro MAC Address
                            pMACAddress        = 
                              (unsigned long)SVBList[1].list->;
                            if (pMACAddress)
                                pTable[iEntries].MACAddress[0] = 
                                       *(unsigned char *)(pMACAddress + 0);
                                pTable[iEntries].MACAddress[1] = 
                                       *(unsigned char *)(pMACAddress + 1);
                                pTable[iEntries].MACAddress[2] = 
                                       *(unsigned char *)(pMACAddress + 2);
                                pTable[iEntries].MACAddress[3] = 
                                       *(unsigned char *)(pMACAddress + 3);
                                pTable[iEntries].MACAddress[4] = 
                                       *(unsigned char *)(pMACAddress + 4);
                                pTable[iEntries].MACAddress[5] = 
                                       *(unsigned char *)(pMACAddress + 5);

                            // Entry Type
                            pTable[iEntries].Type    = 
                             (unsigned long)SVBList[2].list->value.asnValue.number;

                            // Type must be one of (1, 2, 3, 4)
                            if (pTable[iEntries].Type>=1 && pTable[iEntries].Type<=4)
                                iEntries++;        // Move to next array position
                        break;    // If error exit do-while
    while(iEntries < TableLength);

    // Frees the memory allocated for the specified object identifiers

    return iEntries;    // Return number of Entries

Edit ARP entries

The function EditEntry adds/modifies/removes ARP entries. It adds dynamic entries like arp.exe 11-22-33-44-55-66, static entries like arp.exe –s 11-22-33-44-55-66, or removes entry like arp.exe –d When you add a new entry, if the entry IP address does not exist in the ARP table, the entry will be added to the table. Else, if the entry IP address already exists in the ARP table, the entry will be updated. To remove an entry, you need only the IP address to identify the entry on the NIC interface. The MAC address is not needed in the remove operation. The function takes four parameters: the IPAddress array of 4 BYTEs, 4 octs of IP Address, MACAddress array of 4 BYTEs, 6 octs of the MAC Address Type Entry type (2:Remove, 3:Dynamic, 4:Static) AdapterIndex - NIC Adapter index number. I've used four OIDs to set the ARP table entries: OID[0] = "", to set the interface index of the entry OID[1] = "", to set MAC address OID[3] = "", to set IP address OID[2] = "", to set the entry type (Static or Dynamic), or Remove entry.

// Function:    EditEntry: Add/Modify/Remove ARP entry for specific NIC interface.
// Parameters:
//    IPAddress       Array of 4 BYTES, 4 octs of IP Address
//    MACAddress      Array of 4 BYTES, 6 octs of MAC Address
//    Type            Entry type (2:Remove, 3:Dynamic, 4:Static)
//    AdapterIndex    NIC Adapter index number
// Returns:
//                    TRUE if set successfully, FALSE otherwise.
BOOL CARP::EditEntry(unsigned char IPAddress[4], unsigned char MACAddress[6], 
                     unsigned long Type, int AdapterIndex)
    if (!bInitialized)
        return 0;

    SnmpVarBindList     SVBList;
    SnmpVarBind         SVBVars[4];
    UINT                OID[4][10];
    AsnInteger32        aiErrorStatus, aiErrorIndex;
    BOOL                bReturn    = FALSE;

    //    Fill array of 4 OIDs
    //    OID[0]    : "", ipNetToMediaIfIndex
    //                The interface on which this entry's equivalence is effective
    //    OID[1]    : "", ipNetToMediaPhysAddress
    //                The media-dependent 'physical' address
    //    OID[2]    : "", ipNetToMediaNetAddress
    //                The IpAddress corresponding to the media-dependent 'physical' address
    //    OID[3]    : "", ipNetToMediaType
    //                Entry type: 1:Other, 2:Invalid(Remove), 3:Dynamic, 4:Static
    for (int count=0; count<4; count++)
        OID[count][0]        = 1;
        OID[count][1]        = 3;
        OID[count][2]        = 6;
        OID[count][3]        = 1;
        OID[count][4]        = 2;
        OID[count][5]        = 1;
        OID[count][6]        = 4;
        OID[count][7]        = 22;
        OID[count][8]        = 1;
        OID[count][9]        = 1 + count;

        case 0:
            //    OID[0]    : "", ipNetToMediaIfIndex
            //                The interface on which this entry's equivalence is effective
            SVBVars[count].value.asnType                = ASN_INTEGER;
            SVBVars[count].value.asnValue.number        = AdapterIndex;

        case 1:
            //    OID[1]    : "", ipNetToMediaPhysAddress
            //                The media-dependent 'physical' address
            SVBVars[count].value.asnType                = ASN_OCTETSTRING;
            SVBVars[count] = MACAddress;
            SVBVars[count].value.asnValue.string.length = 6;    // MAC Address length
            SVBVars[count].value.asnValue.string.dynamic= FALSE;

        case 2:
            //    OID[2]    : "", ipNetToMediaNetAddress
            //                The IpAddress corresponding
            //                to the media-dependent 'physical' address
            SVBVars[count].value.asnType                = ASN_IPADDRESS;
            SVBVars[count] = IPAddress;
            SVBVars[count].value.asnValue.string.length = 4;    // IP Address length
            SVBVars[count].value.asnValue.string.dynamic= FALSE;

        case 3:
            //    OID[3]    : "", ipNetToMediaType
            //                Entry type: 2:Remove, 3:Dynamic, 4:Static
            SVBVars[count].value.asnType                = ASN_INTEGER;
            SVBVars[count].value.asnValue.number        = Type;
        AsnObjectIdentifier    AsnOID = {sizeof(OID[count])/sizeof(UINT), OID[count]};
        SnmpUtilOidCpy(&SVBVars[count].name, &AsnOID);

    SVBList.len     = 4;
    SVBList.list    = SVBVars;

    aiErrorStatus   = 0;
    aiErrorIndex    = 0;

    // Set information of entry (4 OIDs)
    if (pfnSnmpExtensionQuery(SNMP_PDU_SET, &SVBList, &aiErrorStatus, &aiErrorIndex))
        if (aiErrorStatus == SNMP_ERRORSTATUS_NOERROR)
            bReturn = TRUE; // If success set bReturn = true

    // Frees the memory allocated for the specified object identifiers

    return bReturn;        // TRUE if set successfully, FALSE otherwise.

Also, you can use the same way with suitable OIDs to add/modify/remove route table information, see some of the RFC1213 identifiers:

mib-2                   node
system                  node
sysDescr                scalar
sysObjectID             scalar
sysUpTime               scalar
sysContact              scalar
sysName                 scalar
sysLocation             scalar
sysServices             scalar
interfaces              node
ifNumber                scalar
ifTable                 table
ifEntry                 row
ifIndex                 column
ifDescr                 column
ifType                  column
ifMtu                   column
ifSpeed                 column
ifPhysAddress           column
ifAdminStatus           column
ifOperStatus            column
ifLastChange            column
ifInOctets              column
ifInUcastPkts           column
ifInNUcastPkts          column
ifInDiscards            column
ifInErrors              column
ifInUnknownProtos       column
ifOutOctets             column
ifOutUcastPkts          column
ifOutNUcastPkts         column
ifOutDiscards           column
ifOutErrors             column
ifOutQLen               column
ifSpecific              column
at                      node
atTable                 table
atEntry                 row
atIfIndex               column
atPhysAddress           column
atNetAddress            column
ip                      node
ipForwarding            scalar
ipDefaultTTL            scalar
ipInReceives            scalar
ipInHdrErrors           scalar
ipInAddrErrors          scalar
ipForwDatagrams         scalar
ipInUnknownProtos       scalar
ipInDiscards            scalar
ipInDelivers            scalar
ipOutRequests           scalar
ipOutDiscards           scalar
ipOutNoRoutes           scalar
ipReasmTimeout          scalar
ipReasmReqds            scalar
ipReasmOKs              scalar
ipReasmFails            scalar
ipFragOKs               scalar
ipFragFails             scalar
ipFragCreates           scalar
ipAddrTable             table
ipAddrEntry             row
ipAdEntAddr             column
ipAdEntIfIndex          column
ipAdEntNetMask          column
ipAdEntBcastAddr        column
ipAdEntReasmMaxSize     column
ipRouteTable            table
ipRouteEntry            row
ipRouteDest             column
ipRouteIfIndex          column
ipRouteMetric1          column
ipRouteMetric2          column
ipRouteMetric3          column
ipRouteMetric4          column
ipRouteNextHop          column
ipRouteType             column
ipRouteProto            column
ipRouteAge              column
ipRouteMask             column
ipRouteMetric5          column
ipRouteInfo             column
ipNetToMediaTable       table
ipNetToMediaEntry       row
ipNetToMediaIfIndex     column
ipNetToMediaPhysAddress column
ipNetToMediaNetAddress  column
ipNetToMediaType        column
ipRoutingDiscards       scalar
icmp                    node
icmpInMsgs              scalar
icmpInErrors            scalar
icmpInDestUnreachs      scalar
icmpInTimeExcds         scalar
icmpInParmProbs         scalar
icmpInSrcQuenchs        scalar
icmpInRedirects         scalar
icmpInEchos             scalar
icmpInEchoReps          scalar
icmpInTimestamps        scalar
icmpInTimestampReps     scalar
icmpInAddrMasks         scalar
icmpInAddrMaskReps      scalar
icmpOutMsgs             scalar
icmpOutErrors           scalar
icmpOutDestUnreachs     scalar
icmpOutTimeExcds        scalar
icmpOutParmProbs        scalar
icmpOutSrcQuenchs       scalar
icmpOutRedirects        scalar
icmpOutEchos            scalar
icmpOutEchoReps         scalar
icmpOutTimestamps       scalar
icmpOutTimestampReps    scalar
icmpOutAddrMasks        scalar
icmpOutAddrMaskReps     scalar
tcp                     node
tcpRtoAlgorithm         scalar
tcpRtoMin               scalar
tcpRtoMax               scalar
tcpMaxConn              scalar
tcpActiveOpens          scalar
tcpPassiveOpens         scalar
tcpAttemptFails         scalar
tcpEstabResets          scalar
tcpCurrEstab            scalar
tcpInSegs               scalar
tcpOutSegs              scalar
tcpRetransSegs          scalar
tcpConnTable            table
tcpConnEntry            row
tcpConnState            column
tcpConnLocalAddress     column
tcpConnLocalPort        column
tcpConnRemAddress       column
tcpConnRemPort          column
tcpInErrs               scalar
tcpOutRsts              scalar
udp                     node
udpInDatagrams          scalar
udpNoPorts              scalar
udpInErrors             scalar
udpOutDatagrams         scalar
udpTable                table
udpEntry                row
udpLocalAddress         column
udpLocalPort            column
egp                     node
egpInMsgs               scalar
egpInErrors             scalar
egpOutMsgs              scalar
egpOutErrors            scalar
egpNeighTable           table
egpNeighEntry           row
egpNeighState           column
egpNeighAddr            column
egpNeighAs              column
egpNeighInMsgs          column
egpNeighInErrs          column
egpNeighOutMsgs         column
egpNeighOutErrs         column
egpNeighInErrMsgs       column
egpNeighOutErrMsgs      column
egpNeighStateUps        column
egpNeighStateDowns      column
egpNeighIntervalHello   column
egpNeighIntervalPoll    column
egpNeighMode            column
egpNeighEventTrigger    column
egpAs                   scalar
transmission            node
snmp                    node
snmpInPkts              scalar
snmpOutPkts             scalar
snmpInBadVersions       scalar
snmpInBadCommunityNames scalar
snmpInBadCommunityUses  scalar
snmpInASNParseErrs      scalar
snmpInTooBigs           scalar
snmpInNoSuchNames       scalar
snmpInBadValues         scalar
snmpInReadOnlys         scalar
snmpInGenErrs           scalar
snmpInTotalReqVars      scalar
snmpInTotalSetVars      scalar
snmpInGetRequests       scalar
snmpInGetNexts          scalar
snmpInSetRequests       scalar
snmpInGetResponses      scalar
snmpInTraps             scalar
snmpOutTooBigs          scalar
snmpOutNoSuchNames      scalar
snmpOutBadValues        scalar
snmpOutGenErrs          scalar
snmpOutGetRequests      scalar
snmpOutGetNexts         scalar
snmpOutSetRequests      scalar
snmpOutGetResponses     scalar
snmpOutTraps            scalar
snmpEnableAuthenTraps   scalar


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Usama El-Mokadem
Engineer UEEPC
Egypt Egypt
Programming Languages: C/C++, C#, .NET, Assembly (x86, Win32), and Classic Visual Basic.

Brainbench: 4611463

Comments and Discussions

Questionwill it get all IP addresses from the network Pin
shivam dhoot2-Jul-14 17:53
Membershivam dhoot2-Jul-14 17:53 
AnswerRe: will it get all IP addresses from the network Pin
Usama El-Mokadem17-Nov-14 17:37
MemberUsama El-Mokadem17-Nov-14 17:37 
Generalmight be interesting... Pin
DaveHowe5-Nov-10 0:31
MemberDaveHowe5-Nov-10 0:31 
GeneralMemory leak Pin
Simus18-Oct-10 2:33
MemberSimus18-Oct-10 2:33 
GeneralAdding a subtree Pin
LenochkaONX9-Oct-08 23:09
MemberLenochkaONX9-Oct-08 23:09 
GeneralVery very good. Pin
madar123#11-Mar-08 23:54
Membermadar123#11-Mar-08 23:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.