ARP報文發送的可視化實現


一、安裝VS2013,下載wpdpack,為VS2010配置WinpCap環境:

  ⑴首先在View中選擇Property Manager,然后展開工程,再展開Debug|Win32 ,接着右擊 Mircrosoft.Cpp.Win32.user選擇Properties(此處設置全局有效)

  ⑵之后分三步:

  ①設置環境目錄

    在VC++ Directiories中 Include Directories和Library Directories中添加路徑。

    假如將wpdpack放到c盤。則:

    Include Directories:c:/wpdpack/Include;

    Library Directories:c:/wpdpack/Lib;

    注意分號!

  ②設置編譯條件

    C/C++下Preprocessor(預處理器)的Preprocessor Definitions(預處理定義)

    添加WPCAP;HAVE_REMOTE;

    注意分號,每個預定義符用“;”分開。

  ③設置鏈接器

    Linker(鏈接器)下的Input(輸入)中的Additional Dependencies(附加依賴項)中添加:

    wpcap.lib;ws2_32.lib;(注意分號)

二、使用mfc實現可視化界面:

    目的視圖:

  

    1、新建項目:

      選擇Visual C++ -> MFC -> MFC應用程序 –>修改項目名稱test1 -> 下一步 –> 選擇基於對話框 -> 完成

  2、相關視圖介紹:

      ①解決方案資源管理器:可以看見所有的頭文件和源(.cpp)文件,此程序只需用到test1Dlg.cpp和test1Dlg.h。另外MFC中main函數被封裝起來了,並且我們也並不需要知道main函數在哪,因為我們希望實現的功能通常是觸發某個控件,這個控件的觸發函數為我們實現,並不需要將代碼寫到main函數內。

      ②類視圖:在類視圖中,我們可以看到三個類,此處只需要用到Ctest1Dlg,點擊類名,可以在下方很方便的找到類中的函數和變量。

      ③屬性管理器:在為VS配置全局環境時會用到。

      ④資源視圖:在test1 -> test1.rc -> Dialog -> IDD_TEST1_DIALOG可以看見自己設計的可視化界面。

      ⑤屬性:處理控件時,在此處修改控件的屬性。

    3、相關控件的使用:

      ①靜態文本框Static Text:caption修改文字內容

      ②編輯框Edit Control:Read Only設置是否只讀

    ③IP地址編輯框IP Address Control:用法與普通編輯框一樣,只不過讀取內容時可以使用GetAddress()函數。

    ④組合框Combo Box:Type分為三種:簡易(Simple)組合框、下拉式(Dropdown)組合框和下拉列表式(Drop List)組合框,這里選擇Drop List。

三、詳細設計:

  1.ARP發送中重要方法:

  填充ARP包方法的流程圖:

    

四、添加函數:

  1、 更改各控件ID,並給部分空間增加變量。Combo Box的默認ID更改為IDC_NIC_COMBO,增加控件變量m_comboNic;目的MAC地址的編輯框ID設為IDC_DESTI_MACADDRESS_EDIT,添加控件變量為m_editDesti;目的IP地址的編輯框ID設為IDC_DESTI_IPADDRESS,添加控件變量為m_ipaddressSesti;源MAC地址的編輯框ID設為IDC_SOURCE_MACADDRESS_EDIT,添加控件變量為m_editSource;源IP地址的編輯框ID設為IDC_SOURCE_IPADDRESS,添加控件變量為m_ipaddressSource;結果顯示編輯框ID設為IDC_RESULT_EDIT,添加控件變量為m_editResult。

  2、 依據ARP包的結構定義結構體,並將需要引入的頭文件、結構體和相關常量的定義寫入test1Dlg.h文件中。

#include "stdafx.h"

#include <pcap.h>

#define ETH_ARP         0x0806  //以太網幀類型表示后面數據的類型,對於ARP請求或應答來說,該字段的值為x0806
#define ARP_HARDWARE    1  //硬件類型字段值為表示以太網地址
#define ETH_IP          0x0800  //協議類型字段表示要映射的協議地址類型值為x0800表示IP地址
#define ARP_REQUEST     1   //ARP請求
#define ARP_RESPONSE       2      //ARP應答

//14字節以太網首部
struct EthernetHeader
{
    u_char DestMAC[6];    //目的MAC地址 6字節
    u_char SourMAC[6];   //源MAC地址 6字節
    u_short EthType;         //上一層協議類型,如0x0800代表上一層是IP協議,0x0806為arp  2字節
};

//28字節ARP幀結構
struct ArpHeader
{
    unsigned short hdType;   //硬件類型
    unsigned short proType;   //協議類型
    unsigned char hdSize;   //硬件地址長度
    unsigned char proSize;   //協議地址長度
    unsigned short op;   //操作類型,ARP請求(1),ARP應答(2),RARP請求(3),RARP應答(4)。
    u_char smac[6];   //源MAC地址
    u_char sip[4];   //源IP地址
    u_char dmac[6];   //目的MAC地址
    u_char dip[4];   //目的IP地址
};

//定義整個arp報文包,總長度42字節
struct ArpPacket {
    EthernetHeader ed;
    ArpHeader ah;
};

 

  3、 在Ctest1Dlg::OnInitDialog()中寫入初始化的界面的代碼。

  

/* 獲取本機設備列表 */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        m_comboNic.AddString(_T("Error in pcap_findalldevs!"));
        exit(1);
    }

    /* 打印列表 */
    for (d = alldevs; d; d = d->next)
    {
        ++i;
        if (d->description)
            m_comboNic.AddString(LPCTSTR(CString(d->name)));
        else
            m_comboNic.AddString(_T("(No description available)"));
    }

    if (i == 0)
    {
        m_comboNic.AddString(_T("No interfaces found! Make sure WinPcap is installed."));
        return -1;
    }
    // 默認選擇第一項
    m_comboNic.SetCurSel(0);
    //目的MAC地址編輯框中默認顯示"00-00-00-00-00-00"
    SetDlgItemText(IDC_EDIT1, _T("00-00-00-00-00-00"));

 

  4、 在確認按鈕的響應函數內添加以下代碼:

// 獲取組合框控件的列表框中選中項的索引   
    inum = m_comboNic.GetCurSel();
    /* 跳轉到選中的適配器 */
    for (d = alldevs, i = 0; i<= inum - 1; d = d->next, i++);
    /* 打開設備 */
    if ((adhandle = pcap_open(d->name,          // 設備名
        65536,            // 65535保證能捕獲到不同數據鏈路層上的每個數據包的全部內容
        PCAP_OPENFLAG_PROMISCUOUS,    // 混雜模式
        1000,             // 讀取超時時間
        NULL,             // 遠程機器驗證
        errbuf            // 錯誤緩沖池
        )) == NULL)
    {
        m_editResult.SetWindowText(_T("Unable to open the adapter. \rIt is not supported by WinPcap"));
        /* 釋放設備列表 */
        pcap_freealldevs(alldevs);
        exit(-1);
    }

    unsigned char sendbuf[42]; //arp包結構大小,42個字節
    BYTE IPByte[4];
    m_ipaddressSesti.GetAddress(IPByte[0], IPByte[1], IPByte[2], IPByte[3]);
    BYTE IPByte2[4];
    m_ipaddressSource.GetAddress(IPByte2[0], IPByte2[1], IPByte2[2], IPByte2[3]);

    CString str;
    char *c;
    BYTE mac[7] = { 0 };//源MAC地址
    m_editSource.GetWindowText(str);//獲取字符串
    c = cs2ca(str);    //CString轉為char*
    sscanf_s(c, "%h2x-%h2x-%h2x-%h2x-%h2x-%h2x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);

    EthernetHeader eh;
    ArpHeader ah;
    if (IsDlgButtonChecked(IDC_RADIO1) == 1) {
        //請求報文
      .....//相應代碼
} else if (IsDlgButtonChecked(IDC_RADIO2) == 1) { //應答報文  .....//相應代碼
} //構造一個ARP請求 memset(sendbuf, 0, sizeof(sendbuf)); //ARP清零 memcpy(sendbuf, &eh, sizeof(eh)); memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah)); //如果發送成功 if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) { m_editResult.SetWindowText(_T("\nPacketSend succeed\n")); } else { m_editResult.SetWindowText(_T("\nPacketSendPacket in getmine Error\n")); } /* 釋放設備列表 */ pcap_freealldevs(alldevs);

 

  其中主要遇到的困難是,如何獲取三個編輯框中用戶輸入的地址,將這種Cstring格式的地址轉為u_char格式的字符數組。IP ADDRESS CONTROL可以使用其函數GetAddress(IPByte[0], IPByte[1], IPByte[2], IPByte[3]);獲得。而MAC地址的編輯框獲得的字符串就不太好轉換了。碰過好多好多坑,試過好多好多方法之后,最終找到一種可行的方法:先把Cstring字符串利用函數轉換為char*型,再使用sscanf將每兩位代表十六進制的字符存在BYTE mac[7]數組中,但是貌似在vs2015中無法使用這個方法。

四、運行效果:

     

    

 

    

    

 

 傳送門:

  1.雞啄米VS2010/MFC教程

  2.WinPcap實戰(一)——發送ARP

  3.用sscanf轉換MAC字符串為BYTE數組時遇到的問題

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM