新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → 利用“侦听-转发”程序破译网管协议 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 2540 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 利用“侦听-转发”程序破译网管协议 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客楼主
    发贴心情 利用“侦听-转发”程序破译网管协议

    一、 开发目的及原理

    ---- 本公司在产品开发过程中,需要研究多种以太网交换机(又称智能集线器)的内部网管信息结构,为此,必须编写出一个“窃听”程序,把网管程序和交换机的通讯内容记录下来加以分析。本人在Visual C++ 6.0下用MFC Socket类编出程序,成功地实现了上述目的。

    ---- 目前,标准的网络管理程序与支持网管的网络设备之间大多采用标准的简单网络管理协议(SNMP)进行通讯。SNMP是一种高层协议,建立于UDP/IP之上。通讯双方按照SNMP格式来传递各种网管信息和控制信息,并能进行事件实时报告或报警,从而使网络管理员能方便及时地控制网络当前的运行情况。

    ---- 网管信息的范围十分广泛,如网络流量,连接状态等,因被管设备的不同而不同,厂家也能依照有关的国际标准自定义自家产品的网管信息。网管信息集中定义于管理信息库(MIB)中,整个体系是一个可扩展的树状结构。一条条的网管信息被包装在SNMP协议包内,再往下传给传输层,转成UDP包,然后通过Socket 机制发送出去。

    ---- 本程序的基本原理是:插到网管程序和被管设备之间“欺上瞒下”,与网管程序通讯时冒充被管设备;与被管设备通讯时冒充网管程序,使二者对本程序“无话不谈”;本程序则暗中有序地记录下谈话内容,然后再“上传下达”,将收到的内容转发给真正的接收者,使谈话继续下去,如此循环不已。

    二、 编程的思路和具体过程

    ---- 本程序不需要复杂的图形界面,因此,只需用Project Wizard开出一个支持Socket而基于对话框的MFC 应用程序即可。对话框的类名为CChatDlg,然后再用资源编辑器在这个对话框上加上一个按钮,面上文字为“Listen”。接收到的所有信息将在Visual C++集成环境的Output窗口中用TRACE语句打出,这样做的目的是能方便及时地看到各种数据,当然也可用别的方法。在本程序中,Client指网管程序,Server指交换机。

    ---- 接着给本项目添加两个类,它们都衍生自CSocket,可调用ClassWizard工具生成。CClientSocket用于接收来自网管程序的UDP数据,而CServerSocket则用于接收来自交换机的UDP数据。这两个类的定义如下:

    class CClientSocket : public CSocket
    {
    // Attributes
    public:

    // Operations
    public:
    CClientSocket(CChatDlg* pdlg);
    virtual ~CClientSocket();

    // Overrides
    public:
    BOOL m_bFirst;
    CChatDlg* pDlg;
    // ClassWizard generated virtual
    function overrides
    //{{AFX_VIRTUAL(CClientSocket)
    public:
    virtual void OnReceive(int nErrorCode);
    //}}AFX_VIRTUAL

    // Generated message map functions
    //{{AFX_MSG(CClientSocket)
    // NOTE - the ClassWizard will
    add and remove member functions here.
    //}}AFX_MSG

    // Implementation
    protected:
    };
    m_bFirst和pDlg是自定义的两个类别成员,
    其作用见下文。

    class CServerSocket : public CSocket
    {
    // Attributes
    public:

    // Operations
    public:
    CServerSocket(CChatDlg* pdlg);
    virtual ~CServerSocket();

    // Overrides
    public:
    CChatDlg* pDlg;
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CServerSocket)
    public:
    virtual void OnReceive(int nErrorCode);
    //}}AFX_VIRTUAL

    // Generated message map functions
    //{{AFX_MSG(CServerSocket)
    // NOTE - the ClassWizard will add
    and remove member functions here.
    //}}AFX_MSG

    // Implementation
    protected:
    };

    然后,在CChatDlg类中加入对
    按钮Listen的处理函数如下:
    void CChatDlg::OnListen()
    {
    pClientSocket = new CClientSocket(this);

    if(pClientSocket != NULL)
    {
    if(!pClientSocket->Create(SNMP_SOCKET_PORT,
    SOCK_DGRAM))
    AfxMessageBox("Can not create ClientSocket !");
    else
    ::EnableWindow(GetDlgItem(IDC_LISTEN)->
    m_hWnd,FALSE);
    }
    else
    {
    AfxMessageBox("Can not new ClientSocket !");
    }
    }
    注意:SNMP_SOCKET_PORT应设为161。

    然后,在CClientSocket中加入
    虚函数OnReceive的实作内容:
    void CClientSocket::OnReceive(int nErrorCode)
    {
    CSocket::OnReceive(nErrorCode);

    unsigned char tmp[MAXTMPSIZE];
    //MAXTMPSIZE是自定义宏,可为1024;
    int i;
    int RecNum;

    UINT ClientPort;
    CString ClientAddress;

    if(m_bFirst)
    {
    m_bFirst = false;

    RecNum = ReceiveFrom(tmp, MAXTMPSIZE,
    ClientAddress, ClientPort);

    if(RecNum > 0)
    {
    TRACE("Received from client, %d bytes :\n", RecNum);
    for(i=0; i<RecNum; i++)
    {
    if(i%10==0)
    TRACE("\n%5d,", tmp[i]);
    else
    TRACE("%5d,", tmp[i]);
    }

    TRACE("\n\n");

    pDlg->CreateServerSocket(ClientAddress, ClientPort);
    pDlg->Send(true, tmp, RecNum);
    }
    else
    AfxMessageBox("Error: fail to Receive from
    client the first time!");
    }
    else
    {
    RecNum = Receive(tmp, MAXTMPSIZE);

    if(RecNum > 0)
    {
    TRACE("Received from client, %d bytes :\n", RecNum);
    for(i=0; i<RecNum; i++)
    {
    if(i%10==0)
    TRACE("\n%5d,", tmp[i]);
    else
    TRACE("%5d,", tmp[i]);
    }

    TRACE("\n\n");

    pDlg->Send(true, tmp, RecNum);
    }
    else
    AfxMessageBox("Error: fail to Receive from client!");
    }

    if(RecNum <= 0)
    {
    AfxMessageBox("Error: fail to Receive from client !");
    return;
    }
    }
    ---- 本段程序的大概意思是:如果本程序首次收到来自网管程序的UDP包,则要记录下它的Socket端口号和IP 地址,这是本程序最关键的地方之一。这样做的原因是:网管通讯开始时一般是由网管程序首先发出SNMP 请求包,所以要先响应网管程序;另一目的是由此获得事先未知的网管程序侦听的Socket端口号和IP地址,然后让CChatDlg由此创建CServerSocket。随后调用CChatDlg的Send函数将收到的UDP包转发给交换机,并在Output窗口按每行10个的格式显示出收到的数据。

    ---- 上段程序中CChatDlg的Send和CreateServerSocket函数的内容如下:

    void CChatDlg::CreateServerSocket
    (CString address, UINT port)
    {
    m_ClientAddress = address;
    m_ClientPort = port;

    pServerSocket = new CServerSocket(this);

    if(pServerSocket != NULL)
    {
    if(!pServerSocket->Create(m_ClientPort,
    SOCK_DGRAM))
    AfxMessageBox("Can not create ServerSocket !");
    }
    else
    AfxMessageBox("Can not new ServerSocket !");
    }

    void CChatDlg::Send(BOOL ToServer,
    unsigned char* buf, int buf_len)
    {
    if(ToServer)
    {
    if(pServerSocket != NULL)
    {
    if(pServerSocket->SendTo(buf, buf_len,
    SNMP_SOCKET_PORT,
    m_ServerAddress)==SOCKET_ERROR)
    AfxMessageBox("Error: fail to send data to
    server !");
    }
    }
    else
    {
    if(pClientSocket != NULL)
    {
    if(pClientSocket->SendTo(buf, buf_len, m_ClientPort,
    m_ClientAddress)==SOCKET_ERROR)
    AfxMessageBox("Error: fail to send data to client !");
    }
    }
    }
    ---- 注意:m_ServerAddress是交换机的IP地址,要事先在CChatDlg的OnInitDialog函数或其他地方设定。

    ---- 最后,要处理接收到的来自于交换机的UDP包,将其中的数据在Output窗口中按每行10个的格式显示出来,然后调用CChatDlg的Send函数将其转发给网管程序。这在CServerSocket类的OnReceive虚函数中实现:

    void CServerSocket::OnReceive(int nErrorCode)
    {
    CSocket::OnReceive(nErrorCode);

    unsigned char tmp[MAXTMPSIZE];
    int i;
    int RecNum;

    RecNum = Receive(tmp, MAXTMPSIZE);

    if(RecNum > 0)
    {
    TRACE("Received from server, %d bytes:\n", RecNum);

    for(i=0; i<RecNum; i++)
    {
    if(i%10==0)
    TRACE("\n%5d,", tmp[i]);
    else
    TRACE("%5d,", tmp[i]);
    }

    TRACE("\n\n");

    pDlg->Send(false, tmp, RecNum);
    }
    else
    {
    i = GetLastError();
    TRACE("RecNum = %d,
    GetLastError() = %d\n", RecNum, i);
    AfxMessageBox("Error: fail to Receive from server!");
    }
    }
    ---- 以上就是本程序的主要功能部分,其中有一些变量因篇幅原因未作详细解释,但不影响对程序的理解。

    三、 运行过程

    ---- 分别在两台机器上装上本程序和网管程序,将它们连上交换机,先运行本程序,点Listen按钮,然后运行网管程序。一般的网管程序运行时,需要设置被管设备的IP的地址,此时,要将其设为本程序所在机器的IP地址,使网管程序将所有的SNMP包发给本程序。

    ---- 之后两程序应能正确运行(如果不行,可能要将上述过程多重复几次。),在Output窗口可以看到数据源源不断地显示出来,这真是对网管过程的真实记录!当数据量足够后,结束本程序,可以看到网管程序界面上显示出“设备已断开连接!”的提示信息。然后可以将Output窗口中的数据拷贝到文本文件中,按照SNMP的格式和编码规则进行详细分析,网管协议就由此慢慢地破解出来了。

    ---- 以上程序在Visual C++ 6.0下编译通过并运行成功,实践效果很好。


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/11/20 16:22:00
     
     GoogleAdSense射手座1984-11-30
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/9/21 13:47:52

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    58.594ms