您的位置:逆风者 VC++ 正文
 添加时间:2008-03-21 原文发表:2008-03-21 人气:87 来源:vckbase.com

作者:Usama El-Mokadem
翻译:VCKBASE.PowerCPP

下载源代码


逆风者

介绍


这个工具像Windows命令行工具arp.exe一样显示和修改IP/物理地址转表(ARP表).
该工具将做两件事情:
1)显示ARP表
2)添加、删除、修改ARP表
这两项工作通过SNMP(简单网络管理协议)扩展库来完成。

通过SNMP处理IP和MAC地址

你可以通过SNMP读取或修改ARP表,通过SNMP得到或设置对象信息。SNMP命令的请求与响应是依靠MIB(管理信息库)来完成的。
MIB为树装结构,MIB拥有所有为我们所用的可管理对象,更多的信息可以参考RFC1213(http://www.ietf.org/rfc/rfc1213.txt),
也可以查看文件:%SystemRoot%\system32\*.mib,您可以用notepad.exe打开并查看%SystemRoot%\system32\mib_ii.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.
}   
你也可以用同样的方法采用合适的OID,添加、修改、删除路由表信息,具体参考RFC1213。
相关文章

VC6下的GDI+双缓冲
运动搜索算法之钻石搜索(Ver1.0)
基于GDI+的数字图像处理
MFC 通用控件的初始化
浅谈输入法编程
多线程管理类
如何实现由列表控件控制的属性表
动态创建控件支持事件响应并可保存与读取
简单录、放音并保存为wav文件程序
I2C通信
VC6绘制3D饼状图
强制编译时约束
在C++中实现C#的delegate机制
一个工业控制管道流动控件的实现
Thunk 技术的一个改进
直接调用类成员函数地址
自定义控件—特效列表控件
VC6绘制3D饼状图 - 完美版
通用 Thunk
从printf谈可变参数函数的实现

相关评论


本文章所属分类:首页 VC++

  热门关键字: