📄 arp.h
字号:
/*
* Copyleft Abelworkshop.
* 文件名称:arp.h
* 摘 要:抓包程序,通过向局域网上发送ARP请求来获得活动主机的IP地址与MAC对应关系
* 单 位:信息学院
* 作 者:罗涛,2120060434
* 完成日期:2006年10月25日
*/
#include <stdlib.h>
#include <stdio.h>
//#include <pcap.h>
#include "pcap.h"
#include <fstream>
using namespace std;
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "wpcap.lib")
#define BROADMAC {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} //广播MAC
#define EH_TYPE 0x0806 //ARP类型
#define ARP_HRD 0X0001 //硬件类型:以太网接口类型为1
#define ARP_PRO 0x0800 //协议类型:IP协议类型为0X0800
#define ARP_HLN 0x06 //硬件地址长度:MAC地址长度为6B
#define ARP_PLN 0x04 //协议地址长度:IP地址长度为4B
#define ARP_REQUEST 0x0001 //操作:ARP请求为1
#define ARP_REPLY 0x0002 //操作:ARP应答为2
#define ARP_THA {0,0,0,0,0,0} //目的MAC地址:ARP请求中该字段没有意义,设为0;ARP响应中为接收方的MAC地址
#define ARP_PAD {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
#define SPECIAL 0x70707070 //定义获得自己MAC地址的特殊源IP,112.112.112.112
#define BUFFERSIZE 24 //缓冲区足够大的话,守候线程可以更加从容干自己喜欢干的事儿!20061027
#define ETH_HRD_DEFAULT {BROADMAC, {0,0,0,0,0,0}, htons(EH_TYPE)}
#define ARP_HRD_DEFAULT {htons(ARP_HRD), htons(ARP_PRO), ARP_HLN, ARP_PLN, htons(ARP_REQUEST), {0,0,0,0,0,0}, 0, ARP_THA, 0, ARP_PAD}
typedef unsigned char uchar;
typedef unsigned short usint;
typedef unsigned long ulint;
//string seleDevName = "";
uchar* g_chLocalMac = (uchar *)malloc(sizeof(uchar) * 6); //存放本地MAC地址
BOOL g_bThreadWaitingStop = 1;
int g_gotMac = 0;
struct ethernet_head
{
uchar dest_mac[6]; //目标主机MAC地址
uchar source_mac[6]; //源端MAC地址
usint eh_type; //以太网类型
};
struct arp_head
{
usint hardware_type; //硬件类型:以太网接口类型为1
usint protocol_type; //协议类型:IP协议类型为0X0800
uchar add_len; //硬件地址长度:MAC地址长度为6B
uchar pro_len; //协议地址长度:IP地址长度为4B
usint option; //操作:ARP请求为1,ARP应答为2
uchar sour_addr[6]; //源MAC地址:发送方的MAC地址
ulint sour_ip; //源IP地址:发送方的IP地址
uchar dest_addr[6]; //目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址
ulint dest_ip; //目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址
uchar padding[18];
};
struct arp_packet //最终arp包结构
{
ethernet_head eth; //以太网头部
arp_head arp; //arp数据包头部
};
struct SQueryParam
{
CWnd *pWnd;
HTREEITEM hItem;
pcap_if_t* pDvc;
};
int countCh(char* chIn){ //计算字符数组长度
int i = 0;
while (chIn[i++] != 0);
return i;
}
#define IPTOSBUFFERS 12
char* ipTostr(ulint ulIP)
{ // 将一个无符号长整型的机器IP地址转换为字符串类型的用户友好IP格式
static char output[IPTOSBUFFERS][3 * 4 + 3 + 1];
static short which; //定义两个静态数组,可容纳最多12组IP类地址,最大程度防止指针越界!
uchar* chIP;
chIP = (uchar*)&ulIP; //取ulIP的地址,并强制转化为无符号字符型指针
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", chIP[0], chIP[1], chIP[2], chIP[3]);
return output[which];
}
char* macTostr(uchar* chMAC)
{ //将MAC地址的数组变为带“-”的大写的字符可读形式
uchar* uMac = new uchar[18];
for(int i=0; i < 17; i++){
if ((i+1) % 3){
if (!(i % 3)){
if ((chMAC[i/3] >> 4) < 0x0A){
uMac[i] = (chMAC[i/3] >> 4) + 48;
}
else{
uMac[i] = (chMAC[i/3] >> 4) + 55;
}
if ((chMAC[i/3] & 0x0F) < 0x0A){
uMac[i+1] = (chMAC[i/3] & 0x0F) + 48;
}
else{
uMac[i+1] = (chMAC[i/3] & 0x0F) + 55;
}
}
}
else{
uMac[i] = '-';
}
}
uMac[17] = '\0';
return (char*)uMac;
}
char* trimSpace(char* in){ //去掉字符串中多余的空格,对长串连续出现的空格只保留一个空格,以使显示美观
int strLen = 0;
while(in[strLen++] != '\0');
char* chTemp = new char[strLen + 1];
int i = 0;
int j = 0;
while(in[i] != '\0'){
if(in[i] != ' '){
chTemp[j++] = in[i++];
}
else{
chTemp[j++] = in[i++];
while(in[i] == ' ')i++; //下一个是空格就一直朝前找下一个
}
/*chTemp[j++] = in[i++]; //简化不成功!!20061022
if(in[i] == ' ' ){
while(in[i] == ' ')i++;
}*/
}
chTemp[j] = '\0';
return chTemp;
}
/*处理数据包的回调函数示例 //太死板,不灵活,不利于多线程工作,不用!20061023
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){
struct tm *ltime;
char timestr[16];
ltime = localtime(&header->ts.tv_sec); // 转换时间戳为可以阅读的格式
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}*/
//封装ARP请求包
uchar* enArpReqPack(uchar* source_mac, uchar* arp_sha, ulint chLocalIP, ulint arp_tpa, int PackSize)
{
arp_packet arpPackStru = {ETH_HRD_DEFAULT,ARP_HRD_DEFAULT};
//memset(eth_pa.dest_mac,'F',6);
// = {'F','F','F','F','F','F'};
uchar* arpStruToStr = (uchar *)malloc(sizeof(uchar) * PackSize);
memset(arpStruToStr, 0, sizeof(arpStruToStr));
memcpy(arpStruToStr, &arpPackStru.eth.dest_mac, 6);
memcpy(arpStruToStr + 6, source_mac, 6);//new
memcpy(arpStruToStr + 12, &arpPackStru.eth.eh_type, 2);
memcpy(arpStruToStr + 14, &arpPackStru.arp.hardware_type, 2);
memcpy(arpStruToStr + 16, &arpPackStru.arp.protocol_type, 2);
memcpy(arpStruToStr + 18, &arpPackStru.arp.add_len, 1);
memcpy(arpStruToStr + 19, &arpPackStru.arp.pro_len, 1);
memcpy(arpStruToStr + 20, &arpPackStru.arp.option, 2);
memcpy(arpStruToStr + 22, arp_sha, 6);//new
memcpy(arpStruToStr + 28, &chLocalIP, 4);//new
memcpy(arpStruToStr + 32, &arpPackStru.arp.dest_addr, 6);
memcpy(arpStruToStr + 38, &arp_tpa, 4);//new
return arpStruToStr;
}
//获得自己的MAC
uchar* getSelfMac(char* pDvcName, ulint chLocalIP)
{
//int i = 0;//调试时统计需要经过多少次才能获得回包,以设置合理的sleep值
//string j = "";
pcap_t* pAdaptHandle;//打开网卡适配器时用
char errbuf[PCAP_ERRBUF_SIZE + 1];
if((pAdaptHandle = pcap_open_live(pDvcName, 60, 1, 100, errbuf)) == NULL){
//arp包最大长度是60,节省内存资源,不设为65536!并且设为混杂模式以检查发往往000000的包20061012
MessageBox(NULL, "无法打开适配器,可能与之不兼容!", "Note", MB_OK);
return NULL;
}
struct pcap_pkthdr *header;
const u_char *pkt_data;
int res;
usint arp_op;
uchar* arp_sha = (uchar *)malloc(sizeof(uchar) * 6);
ulint arp_spa = 0;
ulint arp_tpa = 0;
uchar source_mac[6] = {0,0,0,0,0,0};
uchar* arp_packet_for_self;
arp_packet_for_self = enArpReqPack(source_mac, source_mac, SPECIAL, chLocalIP, 60);
while(!g_gotMac){
//i++;
pcap_sendpacket(pAdaptHandle, arp_packet_for_self, 60);
Sleep(10);//睡一会,给系统喘息的机会:)
res = pcap_next_ex(pAdaptHandle, &header, &pkt_data);
if(res == 0)continue;
memcpy(&arp_op, pkt_data + 20, 2);
memcpy(arp_sha, pkt_data + 22, 6);
memcpy(&arp_spa, pkt_data + 28, 4);
memcpy(&arp_tpa, pkt_data + 38, 4);
if(arp_op == htons(ARP_REPLY) && arp_spa == chLocalIP && arp_tpa == SPECIAL){
//发现当IP地址冲突时会有意想不到的问题,特在此加强限制条件20061024
//j = char(i+48);
//MessageBox(NULL, j.c_str(), "Note", MB_OK);
g_gotMac = 1;
free(arp_packet_for_self);
pcap_close(pAdaptHandle);
return arp_sha;
}
Sleep(100);//若不成功再等100ms再发,让网卡歇歇:) 20061025
}
free(arp_packet_for_self);
pcap_close(pAdaptHandle);
return arp_sha;
}
//发送ARP请求
#define ID_INDICATOR_INFO 59143
void sendArpReq(pcap_if_t* pDvc,uchar* g_chLocalMac)
{
pcap_addr_t* pAdr = 0;
DWORD dwLocalIP = 0;//存放本地ip地址
ulint arp_tpa = 0;
ulint snd_tpa = 0;
ulint nlNetMask = 0;
int netsize = 0;
const char* pDvcName = pDvc->name;
pcap_t* pAdaptHandle;//打开网卡适配器时用
char errbuf[PCAP_ERRBUF_SIZE + 1];
pAdaptHandle = pcap_open_live(pDvc->name, 60, 0, 100, errbuf);
if(NULL==pAdaptHandle){
//arp包最大长度是60,节省内存资源,不设为65536!并且设为混杂模式以检查发往往000000的包20061021
MessageBox(NULL, "无法打开适配器,可能与之不兼容!", "Send", MB_OK);
return;
}
uchar* arp_packet_for_req;
arp_packet_for_req = enArpReqPack(g_chLocalMac, g_chLocalMac, dwLocalIP, dwLocalIP, 60); //构造包,并将只更改倒数第二个形参,在字符串里对之进行局部更改!效率高得多,不要重复申请STRUCT,会浪费大量内存空间20061024
for (pAdr = pDvc->addresses; pAdr; pAdr = pAdr->next){
if (g_bThreadWaitingStop) break;
dwLocalIP = ((struct sockaddr_in *)pAdr->addr)->sin_addr.s_addr;
if (0==dwLocalIP) continue;//可能网卡没有接网线
nlNetMask = ((struct sockaddr_in *)(pAdr->netmask))->sin_addr.S_un.S_addr; //得到子网掩码
netsize = ~ntohl(nlNetMask);
arp_tpa = ntohl(dwLocalIP & nlNetMask); //获得的IP地址是网络序的,必须转为主机序
memcpy(arp_packet_for_req + 28, &dwLocalIP, 4); //将字串中源IP设为本次得到的本地IP
for (int i=0; i < netsize; i++){
if (g_bThreadWaitingStop) break;
arp_tpa++; //第一个循环对于初始化的x.x.x.0的地址不用发,是子网号20061027
snd_tpa=htonl(arp_tpa);
if (snd_tpa==dwLocalIP)continue;//不对自己发ARP请求包,也会产生地址冲突?原因何在?
CString strInfo;
strInfo.Format("查找%s",ipTostr(snd_tpa));
AfxGetApp()->m_pMainWnd->PostMessage(UM_SET_STATUSBAR_TEXT,ID_INDICATOR_INFO,LONG(new CString(strInfo)));
memcpy(arp_packet_for_req + 38, &snd_tpa, 4);//目的IP在子网范围内按序增长
pcap_sendpacket(pAdaptHandle, arp_packet_for_req, 60);
Sleep(15);
}
}
free(arp_packet_for_req);
AfxGetApp()->m_pMainWnd->PostMessage(UM_SET_STATUSBAR_TEXT,ID_INDICATOR_INFO,LONG(new CString("查找完毕")));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -