MFC:使用SNMP编辑(添加/删除/修改)ARP表

来源:互联网 发布:php邮件发送源码 编辑:程序博客网 时间:2024/06/05 02:12
MFC:使用SNMP编辑(添加/删除/修改)ARP表

本文章永久地址 http://www.limou.net/?p=306
介绍
这个工具像Windows命令行工具arp.exe一样显示和修改IP/物理地址转表(ARP表)。该工具将做两件事情。


显示ARP表
添加、删除、修改ARP表
这两项工作通过SNMP(简单网络管理协议)扩展库来完成。


通过SNMP处理IP和MAC地址
你可以通过SNMP读取或修改ARP表,通过SNMP得到或设置对象信息。SNMP命令的请求与响应是依靠MIB(管理信息库)来完成的。MIB为树装结构,MIB拥有所有为我们所用的可管理对象。


下面是MIB ipNetToMediaEntry条目
ipNetToMediaEntry OBJECT-TYPE
              SYNTAX  IpNetToMediaEntry
              ACCESS  not-accessible
              STATUS  mandatory
              DESCRIPTION
                      "Each entry contains one IpAddress to 'physical'
                      address equivalence."
              INDEX   { ipNetToMediaIfIndex,
                        ipNetToMediaNetAddress }
              ::= { ipNetToMediaTable 1 }
MIB通过OID(对象标识)数字来存取对象,每个对象拥有一个数字,子对象拥有父对象的数字和自己的数字,数字之间用”.”来分割。例如:父对象数字为”1″,子对象数字为”3″,则子对象OID为”1.3″,子对象的子对象可以是”1.3.6″,…”1.3.6.1.2.1″等等…


下面是对象树的简单框图:






类的初始化
我们使用SnmpExtensionQuery函数来发送SNMP请求,使用之前我们必须调用SnmpExtensionInit来初始化SNMP扩展代理DLL。
这两个函数包含于Microsoft的inetmib1.dll中。


因此我们在类的构造函数中加载动态库并得到函数的地址,然后调用SnmpExtensionInit初始化SNMP扩展代理DLL。


下面是CARP类的构造函数


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


CARP::CARP()
{
    // 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, "SnmpExtensionInit");
        pfnSnmpExtensionQuery   = (PFNSNMPEXTENSIONQUERY) GetProcAddress(hMIBLibrary, "SnmpExtensionQuery");


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


            bInitialized        = pfnSnmpExtensionInit(0, &hPollForTrapEvent, &aoiSupportedView);
        }
    }
    else
    {
        // If fail to get addresses, bInitialized = false
        bInitialized            = FALSE;
        AfxMessageBox(_T("Load library fail"));
    }
}
得到ARP条目
函数GetEntries类似arp.exe -a,可以得到ARP条目,函数有三个参数:


PTable指针指向arpTable结构数组,用于填充IP和MAC地址。
TableLength是数组长度
AdapterIndex是NIC适配器的编号。
使用3个OID来得到ARP表条目:OID[0] = “1.3.6.1.2.1.4.22.1.1″ ,得到接口索引号。然后和OID[1] = “1.3.6.1.2.1.4.22.1.2″比较,得到IP和MAC地址OID[2] = “1.3.6.1.2.1.4.22.1.4″, 得到条目类型(静态或动态)


//-----------------------------------------------------------------------
// 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]    : "1.3.6.1.2.1.4.22.1.1", ipNetToMediaIfIndex
    //                The interface on which this entry's equivalence is effective
    //
    //    OID[1]    : "1.3.6.1.2.1.4.22.1.2", ipNetToMediaPhysAddress
    //                The media-dependent 'physical' address
    //
    //    OID[2]    : "1.3.6.1.2.1.4.22.1.4", 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;


        switch(count)
        {
        case 0:
            // Adapter interface
            OID[count][9]    = 1;
            break;


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


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


    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;
    do
    {
        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: http://msdn2.microsoft.com/en-us/library/aa378021.aspx
                        //
                        // 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 ".1.3.6.1.4.1.77.1", a Get Next
                        // request on ".1.3.6.1.4.1.77.1.5.1" would result in a modified name field of ".1.3.6.1.4.1.77.2".
                        // This signals the SNMP service to continue the attempt to resolve the variable bindings
                        // with other extension agents
                        //-----------------------------------------------------------------------


                        if(SnmpUtilOidNCmp(&SVBVars[0].name, &AsnOID0, AsnOID0.idLength))
                            break;
                        if(SnmpUtilOidNCmp(&SVBVars[1].name, &AsnOID1, AsnOID1.idLength))
                            break;
                        if(SnmpUtilOidNCmp(&SVBVars[2].name, &AsnOID2, AsnOID2.idLength))
                            break;


                        // 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->value.asnValue.string.stream;
                            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
                        }
                    }
                    else
                        break;    // If error exit do-while
    }
    while(iEntries < TableLength);


    // Frees the memory allocated for the specified object identifiers
    SnmpUtilOidFree(&SVBVars[2].name);
    SnmpUtilOidFree(&SVBVars[1].name);
    SnmpUtilOidFree(&SVBVars[0].name);


    return iEntries;    // Return number of Entries
}
编辑ARP表条目
EditEntry函数可以添加、修改、删除ARP条目:


添加动态条目,就像:arp.exe 1.2.3.4 11-22-33-44-55-66
添加静态条目,就像:arp.exe –s 1.2.3.4 11-22-33-44-55-66
删除条目,就像:arp.exe –d 1.2.3.4
添加新条目,如果IP地址在ARP表中不存在则添加进去,如果已经存在则被更新。
删除条目,只需要提供NIC接口中的IP地址,MAC地址不需要提供。
函数有四个参数:4字节的IPAddress,6字节的MACAddress,条目类型(2:删除,3:动态,4:静态)


AdapterIndex:NIC适配器编号
使用4个OID设置ARP表条目:


OID[0] = “1.3.6.1.2.1.4.22.1.1″, 设置接口编号
OID[1] = “1.3.6.1.2.1.4.22.1.2″, 设置MAC地址
OID[3] = “1.3.6.1.2.1.4.22.1.3″, 设置IP地址
OID[2] = “1.3.6.1.2.1.4.22.1.4″, 设置条目类型 (静态或动态), 或删除
//-----------------------------------------------------------------------
// 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]    : "1.3.6.1.2.1.4.22.1.1", ipNetToMediaIfIndex
    //                The interface on which this entry's equivalence is effective
    //
    //    OID[1]    : "1.3.6.1.2.1.4.22.1.2", ipNetToMediaPhysAddress
    //                The media-dependent 'physical' address
    //
    //    OID[2]    : "1.3.6.1.2.1.4.22.1.3", ipNetToMediaNetAddress
    //                The IpAddress corresponding to the media-dependent 'physical' address
    //
    //    OID[3]    : "1.3.6.1.2.1.4.22.1.4", 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;


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


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


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


        case 3:
            //    OID[3]    : "1.3.6.1.2.1.4.22.1.4", ipNetToMediaType
            //                Entry type: 2:Remove, 3:Dynamic, 4:Static
            SVBVars[count].value.asnType                = ASN_INTEGER;
            SVBVars[count].value.asnValue.number        = Type;
            break;
        }
        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
    SnmpUtilOidFree(&SVBVars[3].name);
    SnmpUtilOidFree(&SVBVars[2].name);
    SnmpUtilOidFree(&SVBVars[1].name);
    SnmpUtilOidFree(&SVBVars[0].name);


    return bReturn;        // TRUE if set successfully, FALSE otherwise.
}
请继续关注 李木空间 www.limou.net 更多精彩源代码。