Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 软件时空 > 软件相关 > ARP协议浅析(3):付诸实践
【标  题】:ARP协议浅析(3):付诸实践
【关键字】:ARP
【来  源】:http://blog.csdn.net/liuxk99/archive/2007/01/22/1489570.aspx

ARP协议浅析(3):付诸实践

Your Ad Here
ARP协议浅析(3):付诸实践
设计与实现... 6
1网卡的枚举,设置和缓冲区分配... 7
2 如何填充和发送一个ARP... 8
2.1 包的分组格式定义... 8
2.2 填充和发送一个ARP请求包... 9
3监听线程(Sniffer)10
4 解析ARP响应包... 12
5 获得本机IP地址和MAC地址... 13
6 发送线程和接受线程的协调... 14
 
这次研究本意是编写一个用于局域网检测IP地址与MAC对应关系的Application,以获知局域网里IP地址的分配情况。
设计与封装
按照功能来规划模块,通过分析发现以下一些独立的功能是必须实现的:
*         1 网卡的枚举,设置和缓冲区分配;
*         2 填充和发送一个ARP包;
*         3 监听线程(Sniffer)
*         4 解析ARP包;
*         5 获得本机IP MAC地址;
*         6 发送线程和接受线程的同步与协调;
至于如何显示IPMAC信息,比较简单请参考源码。
把每个功能封装在一个函数里面。为了更方便的调用winpcap库函数,笔者封装了一个CWinPcap类。代码的几个关键之处说明一下,其它请参考所附源代码。
1网卡的枚举,设置和缓冲区分配
// success return 0
intCWinPcap::OpenPcap()
{
       WCHAR buf[1024];
       ULONG bufsize;
       int res, i = 0;
       memset ((void*)adapterlist, 0, sizeof(adapterlist));
       res = PacketGetAdapterNames ((char*)buf, &bufsize); // 枚举网卡
       if (res == 0)
       {
              return -1;
       }
       WCHAR *p1, *p2;
       p1 = p2 = buf;
       while ((*p1 != '\0') || (*(p1 - 1) != '\0'))
       {
              if (*p1 == '\0')
              {
                     memcpy (adapterlist[i], p2, 2 * (p1 - p2));
                     p2 = p1 + 1;
                     i++;
              }
              p1++;
       }
       m_iAdapterNum = i;
       m_iSelAdapter = i - 1;
       // 打开最后一个网卡,PC机一般是一个网卡
       m_lpAdapter = PacketOpenAdapter( ((char *)adapterlist + m_iSelAdapter * 1024) );
       if (m_lpAdapter == NULL || (m_lpAdapter->hFile == INVALID_HANDLE_VALUE))
       {
              return -1;
       }
       // 分配sender包空间
       m_lpPacketSender = PacketAllocatePacket();
       if (m_lpPacketSender == NULL)
              return -1;
       return 0;
}
2 如何填充和发送一个ARP
2.1 包的分组格式定义
//////////////////////////////////////////////////////////////////////////
// arp.h 定义以太网arp帧结构,封装了winpcap开发包的重要函数
#include <packet32.h>
#include <ntddndis.h>
#include <stdio.h>
#include <conio.h>
#include "afx.h"
#pragma comment(lib,"ws2_32")
#pragma comment(lib,"packet")
#pragma once
#pragma pack(push,1)
// Ether(DLC) header
typedefstructethdr
{
 unsignedchar   eh_dst[6];       // 以太网目的MAC地址
 unsignedchar   eh_src[6];       // 以太网源MAC地址
 unsignedshort eh_type;   // 帧类型
}ETHDR,*PETHDR;
// ARP分组格式
typedefstructarphdr
{
 unsignedshort arp_hdr;   // 硬件类型
 unsignedshort arp_pro;   // 协议类型
 unsignedchar   arp_hln; // 硬件地址长度
 unsignedchar   arp_pln; // 协议地址长度
 unsignedshort arp_opt;   // ARP/RARP
 unsignedchar   arp_sha[6];     // 发送者地址
 unsignedlong   arp_spa; // 发送者IP地址
 unsignedchar   arp_tha[6];     // 接受者地址
 unsignedlong   arp_tpa; // 接受者IP地址
}ARPHDR,*PARPHDR;
#pragma pack(push)
#define ETH_IP                          0x0800
#define ETH_ARP                      0x0806
#define ARP_REQUEST             0x0001
#define ARP_REPLY                  0x0002
#define ARP_HARDWARE         0x0001
#define max_num_adapter            10
classCWinPcap
{
public:
       /* 分析arp包内容*/
       voidGetData(LPPACKET lp);
       /* 发送arp请求包*/
       int          Sender(ULONG ipCur, ULONG ipMine, BYTE mac[]);
       /* 监听网卡收到的包*/
       int          Sniff();
       /* 获得网卡信息,IP地址和MAC地址*/
       voidGetNetInfo(sockaddr_in &sin, CString &strMAC, BYTE mac[]);
       CWinPcap()
       {
              OpenPcap();
       };
       ~CWinPcap()
       {
              ClosePcap();
       };
       /* 打开网卡并初始化*/
       int          OpenPcap();
       /* 关闭网卡*/
       voidClosePcap();
      
private:
       char        adapterlist[max_num_adapter][1024];  
       /* 网卡*/
       LPADAPTER m_lpAdapter;
       /* 帧缓冲*/
       LPPACKET    m_lpPacketReceiver,
                            m_lpPacketSender;
       int                 m_iAdapterNum;
       int                 m_iSelAdapter;
       npf_if_addr    m_netinfo;
};
2.2 填充和发送一个ARP请求包
/********************************************************************
功能       供发送线程调用,发送一个arp请求包
参数
       ipCur      目标IP地址
       ipMine    本机IP地址
       mac[]      网卡MAC地址                                                                       
********************************************************************/
intCWinPcap::Sender(ULONG ipCur, ULONG ipMine, BYTE mac[])
{
       char              pBufSend[1024];
       ETHDR          eth;
       ARPHDR       arp;
       // Fill the ARP request packets.
       int i;
       for (i = 0; i < 6; i++)
       {
              eth.eh_dst[i] = 0xff;
              arp.arp_tha[i] = 0x00;
       }
       // {填充DLC头和ARP
       eth.eh_type     = htons(ETH_ARP);
       memcpy(eth.eh_src, mac, 6);
      
       arp.arp_hdr     = htons(ARP_HARDWARE);
       arp.arp_pro     = htons(ETH_IP);
       arp.arp_hln     = 6;
       arp.arp_pln     = 4;
       arp.arp_opt     = htons(ARP_REQUEST);
      
       memcpy(arp.arp_sha, mac, 6);
       arp.arp_spa     = htonl(ipMine);
       arp.arp_tpa = htonl(ipCur);
       // }
      
       memset(pBufSend, 0, sizeof(pBufSend));
       memcpy(pBufSend, &eth, sizeof(eth));
       // 装配完整arp
       memcpy(pBufSend + sizeof(eth), &arp, sizeof(arp));
      
       PacketInitPacket(m_lpPacketSender, pBufSend, sizeof(eth) + sizeof(arp));
       if(PacketSendPacket(m_lpAdapter, m_lpPacketSender,TRUE)==FALSE)
       {
              return -1;
       }
       return 0;
}
3监听线程(Sniffer)
线程函数体实际执行的函数:
intCWinPcap::Sniff()
{
       staticCIPFluxDlg *pdlg = (CIPFluxDlg *)AfxGetMainWnd();
 char recvbuf[1024*250];
       DWORD res = 0;
      
       // {初始化网卡,设置为混合模式NDIS_PACKET_TYPE_PROMISCUOUS
 if(PacketSetHwFilter(m_lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE)
 {
        //printf("Warning: Unable to set the adapter to promiscuous mode\n");
 }
      
 if(PacketSetBuff(m_lpAdapter, 500*1024)==FALSE)
 {
        //printf("PacketSetBuff Error: %d\n",GetLastError());
        return -1;
 }
      
 if(PacketSetReadTimeout(m_lpAdapter, 1)==FALSE)
 {
        //printf("Warning: Unable to set the timeout\n");
 }
      
 if((m_lpPacketReceiver=PacketAllocatePacket())==FALSE)
 {
        //printf("PacketAllocatePacket receive Error: %d\n",GetLastError());
        return -1;
 }
      
 PacketInitPacket(m_lpPacketReceiver, (char *)recvbuf, sizeof(recvbuf));    
       // }
       // {接受包
       do
       {
              if(PacketReceivePacket(m_lpAdapter, m_lpPacketReceiver, TRUE) == FALSE)
              {
                     if(GetLastError() == 6)
                            return 0;
                     return -1;
              }
              GetData (m_lpPacketReceiver); // 解析包的内容
              if (pdlg->m_bStop == TRUE)
                     break;
       }while (1);
       // }
       ResetEvent(pdlg->m_hEvent); // 辅助函数
       return 0;
}
4 解析ARP响应包
/********************************************************************
功能      从接受到的包中提取和解析出ARP包个字段
参数     
       lp    网卡接受到的包的缓冲区指针
********************************************************************/
voidCWinPcap::GetData(LPPACKET lp)
{
       ULONG ulOffset = 0, ulBytesReceived;
       char *buf = NULL;
       char *pChar, *pBase;
       structbpf_hdr *phdr = NULL;
       structsockaddr_in sin;
       ETHDR   *pEther;
       ARPHDR       *pArp;
       //IPHDR *pIphdr;
       CString strIP, strMAC;
       staticCIPFluxDlg *pdlg = (CIPFluxDlg *)AfxGetMainWnd();
      
       buf = (char*)lp->Buffer;
       ulBytesReceived = lp->ulBytesReceived;
       while (ulOffset < ulBytesReceived)
       {
              phdr = (structbpf_hdr *)(buf + ulOffset);
              ulOffset += phdr->bh_hdrlen;
              pChar = (char *)(buf + ulOffset);
        pBase = pChar;
        ulOffset = Packet_WORDALIGN(ulOffset + phdr->bh_caplen);
             
        pEther = (PETHDR)pChar;                    
        pArp   = (PARPHDR)(pChar + sizeof(ETHDR));
             
              // receive ARP reply packets which contain IP address and relative MAC address
              // 受到arp响应包,包含IP地址和相关的MAC地址
              if (pEther->eh_type == htons(ETH_ARP) && pArp->arp_opt == htons(ARP_REPLY))
              {
                     sin.sin_addr.s_addr = pArp->arp_spa;
                     strIP.Format("%-16s", inet_ntoa(sin.sin_addr));
                     CString str;
                     str.Format("%02X", pEther->eh_src[0]);
                     strMAC = str;
                     for (int i = 1; i < 6; i++)
                     {
                            str.Format ("-%02X", pEther->eh_src[i]);
                            strMAC += str;
                     }
                     pdlg->ShowSearch(strIP, strMAC);
                     SetEvent(pdlg->m_hEvent);
              }
       }
}
5 获得本机IP地址和MAC地址
工程中没有采取Winpcap函数来获得MAC地址,而是采用非常有用的iphelp库函数。
DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen);
/************************************************************************
功能       获得本机网卡的IP地址,物理地址,涉及到<ntddndis.h>
参数      
       sin          IP地址
       strMAC   MAC地址16进制表达
       mac[]      MAC地址字节表达
************************************************************************/
voidCWinPcap::GetNetInfo(sockaddr_in &sin, CString &strMAC, BYTE mac[])
{
       PIP_ADAPTER_INFO pAdapterInfo = NULL;
       char ch;
       long sizeinfo;
       ULONG size = 0;
       int res = 0;
       sizeinfo = sizeof(m_netinfo);
       if (m_lpAdapter)
       {
              // 先获得ip地址
              res = PacketGetNetInfoEx (adapterlist[m_iSelAdapter], &m_netinfo, &sizeinfo);
              if (res)
              {
                     sin = *(structsockaddr_in *)&m_netinfo.IPAddress;
              }
              else
              {
                     strMAC = "FF-FF-FF-FF-FF-FF";
              }
              // 试图获得AdapterInfosize返回需要的缓冲区的大小
              res = GetAdaptersInfo ((PIP_ADAPTER_INFO)&ch, &size);
              if (res == ERROR_BUFFER_OVERFLOW)
              {
                     pAdapterInfo = (PIP_ADAPTER_INFO)malloc (sizeof(IP_ADAPTER_INFO));
                     res = GetAdaptersInfo(pAdapterInfo, &size);
                     if (res == 0)
                     {
                            CString str;
                            BYTE *pch = pAdapterInfo->Address; // 导出mac地址16进制表达
                            memcpy (mac, pch, 6);
                            for (int i = 0; i < 6; i++)
                            {
                                   if (i)
                                          strMAC += "-";
                                   str.Format("%02X", *(pch + i));
                                   strMAC += str;
                            }
                     }
                     free (pAdapterInfo);
              }
       }
}
6 发送线程和接受线程的协调
只是简单的多个发送线程,一个监听线程,没有涉及同步问题。
voidCIPFluxDlg::OnBtnStart()
{
       int nTotal = 0;
       ULONG ipFirst, ipLast;
       ULONG ulStartIP = 0;
       m_bStop = FALSE;
       staticBOOL bInit = FALSE;
       m_IPFirst.GetAddress(ipFirst);
       m_IPLast.GetAddress(ipLast);
       nTotal = ipLast - ipFirst + 1;
       m_lstIP.DeleteAllItems();
       GetDlgItem (IDC_BTN_START)->EnableWindow (FALSE);
      
       // 生成一次监听线程
       if (bInit == FALSE)
       {
              m_hSniffer = AfxBeginThread(_tFuncReceiver, (void*)this);
              bInit = TRUE;
       }
       Sleep (300);
       m_IPFirst.GetAddress(ulStartIP);
       for (int i = 0; i < nTotal; i++)
       {
              m_ipCur = ulStartIP + i;
              m_hSender = AfxBeginThread(_tFuncSender, (void*)this);
              // 等待上一个线程结束
              WaitForSingleObject (m_hSender, INFINITE);
       }
       m_bStop = TRUE;
       GetDlgItem (IDC_BTN_START)->EnableWindow (TRUE);
}
 
怎样开好项目开工会:【上一篇】
瑞星网站的XSS漏洞---同上次的工商银行漏洞:【下一篇】
【相关文章】
  • 基于.NET 2.0的GIS开源项目SharpMap分析手记(五):WebGIS原理分析及思考
  • 防SYN洪水攻击、防ARP病毒的路由器
  • Websharp——开源.Net应用系统框架
  • SharpDevelop学习笔记(6)—— AddIn构建指南
  • Csharp Enum的应用,实在方便!---转自网友CK兔子
  • 局域网络环境下ARP欺骗攻击及安全防范策略
  • 设置代理ARP(Debian)
  • Understanding and Configuring Dynamic ARP Inspection
  • SharpDevelop学习笔记(5)—— AddIns系统详解
  • 基于.NET 2.0的GIS开源项目SharpMap分析手记(四):地图数据访问机制分析
  • 【随机文章】
  • Subject CN中的下划线与IIS Client Cert Mapping
  • SA299第十三章读书笔记
  • Windows XP 下安装配置声卡
  • 轻轻松松抓图标源代码
  • PDF In-The-Box v1.6 For Delphi4567
  • JSP标准标签库(JSTL)介绍
  • 无盘工作站安装和调试中的十大经典误区 zt
  • 2007年金山软件校园招聘湖大站笔试题
  • java中关于int值的奇偶判断
  • "新视通"业务解决方案
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.