C/C++手动构造ARP包并发送至网络
2015-08-07 16:52
1146 查看
tip:由于没有及时整理,现在按之前上交的报告来截取内容,希望对有这个需求的朋友有所帮助。如果有错误请批评指出。。
所选题目:
1. 在熟悉ARP协议并了解Winpcap编程的前提下,构造ARP包,选择并打开网卡,将ARP包发送出去。运行格式:程序名源IP地址目的IP地址目的MAC地址flag
源 IP 目的IP 源MAC FLAG
( flag=0: ARP请求flag=1: ARP应答)
1.要求及功能
按照题目要求,成功发送ARP包到网络( flag=0: ARP请求flag=1: ARP应答)2.原理及方法
通过WinPcap的功能函数pcap_findalldevs_ex来获取设备列表,然后选择设备中的某个设备打开,此时准备好构造一个arp包使用打开的设备。Arp包采用结构体来构造,并且嵌套在以太网的结构体内。这里最需要说明的一点是,必须使用#pragma pack(1)命令使得内存对齐,否则编译器自动对齐,会在arp包的数据之间填充一些字节来自动对齐,这样会使得arp的数据包出错。MakeArp函数以一个_ARP * 作为参数,对它的变量进行赋值。这样就构造好了一个arp包。然后使用pcap_sendpacket函数来将数据包原样发送到网络中。最后关闭设备即可。
原理可以简述为如下图所示:
3.实验环境及平台搭建
实验环境:语言:C/C++
编译器:VS2013
操作系统:win7 旗舰版64位
处理器:Intel(R) Core(TM) i5-3317U CPU @1.70GHz
内存:8G
搭建winpcap过程:
到winpcap官网http://www.winpcap.org/ 下载开发包
将其放在自己编译器对应文件夹内。或者单独放在自己工程目录下。编程的时候导入这些文件即可。这样就完成了基本的平台搭建问题。(更好的是根据平台重新编译程序)
4.实验结果及分析
测试:本机ip : 172.18.105.25
目的机ip : 172.18.106.232
本机mac : 20-6a-8a-d1-52-b9
Tip:
本机 ip和mac 可通过函数得到,但由于要在控制台下启动,并且按照老师给的格式,所以最好提前准备好Ip ,可使用ipconfig /all 查看本机ip 。本机mac地址自动填充。
测试参数格式:
源ip 目的ip mac 地址 flag
(flag = 0:mac地址在程序中不采用 ,flag!=0 : mac地址被填充为目的mac地址)
测试数据第一组(request测试):
测试数据:172.18.105.25 172.18.106.232 206a8ad152b9 0 //发送ARP请求
通过wareshark抓包,可以看到该arp已经成功发送出去,并且立马收到两条arp应答。
打开该数据包,查看数据:
可以清晰地看到,所填充数据准确无误。符合数据包格式规范要求。
测试数据第二组(reply测试):
测试数据:172.18.105.25 172.18.106.232 047d7bcdc702 1 //发送ARP响应
通过抓包可以看到:
成功发送应答数据到网络。打开数据包可以查看到数据准确无误。
5.源程序核心函数说明
// to make an arp protocalvoid MakeArp(_ARP * _arp, unsigned char* source_mac_addr, unsigned long source_ip_addr, unsigned long dest_ip_addr);
函数功能:为一个ARP包填充参数
返回值:void
参数说明: _arp:需要填充参数的arp结构体指针
source_mac_addr:源mac地址
source_ip_addr:源ip地址
dest_ip_addr:目的ip地址
void GetDevName(ULONG source_ip, ULONG dest_ip, PUCHAR dest_mac, USHORT flag)
函数功能:得到设备参数,并且发送数据包等
返回值:void
参数说明: source_ip:源ip地址
dest_ip:目的ip地址
dest_mac:目的mac地址
flag:数据包操作码(0 : request , 1 : reply)所有非0即为1
int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
函数功能:得到设备列表
返回值:int
参数说明:
引用官方说明:
source,: a char* buffer that keeps the 'source localtion', according to the new WinPcap syntax. This source will be examined looking for adapters (local or remote) (e.g. source can be 'rpcap://' for local adapters or 'rpcap://host:port' for adapters on a remote host) or pcap files (e.g. source can be 'file://c:/myfolder/').
The strings that must be prepended to the 'source' in order to define if we want local/remote adapters or files is defined in the new Source Specification Syntax .
auth,: a pointer to a pcap_rmtauth structure. This pointer keeps the information required to authenticate the RPCAP connection to the remote host. This parameter is not meaningful in case of a query to the local host: in that case it can be NULL.
alldevs,: a 'struct pcap_if_t' pointer, which will be properly allocated inside this function. When the function returns, it is set to point to the first element of the interface list; each element of the list is of type 'struct pcap_if_t'.
errbuf,: a pointer to a user-allocated buffer (of size PCAP_ERRBUF_SIZE) that will contain the error message (in case there is one).
voidpcap_freealldevs(pcap_if_t *);
函数功能:释放设备列表
返回值:void
参数说明:
参数1:所要释放的设备列表指针
pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
函数功能:关闭所打开的设备
返回值:void
参数说明:
Source: 需要打开的设备名
Snaplen:所能捕获的最大字节数
Flags: 打开模式
Read_timeout:读取超时时间
Auth:引用pcap_findalldevs_ex对该参数的解释
Errbuf: 保存出错的信息
本程序调用示例:
//open the choice
auto pcap = pcap_open(
tmp_->name,
65536,
PCAP_OPENFLAG_PROMISCUOUS, //以混杂模式打开网卡
1000,
NULL,
error);
voidpcap_close(pcap_t *);
函数功能:关闭所打开的设备
返回值:void
参数说明:
参数1:需要关闭的设备指针
// to get the local mac addr
void GetLocalMac(UCHAR * _u_char, PCHAR _adapter);
函数功能:获得本地mac地址
返回值:void
参数说明:_u_char: 用于保存mac地址的指针
_adapter: 所要得到的mac地址所属设备名
// to parse the mac addr
PUCHAR ParseMac(char * mac);
函数功能:将char * 的mac地址转换为 UCHAR 类型的mac地址
返回值:PUCHAR 存放转换后的mac地址指针
参数说明:
mac:待转换的char类型mac地址数组
//begin to send
intpcap_sendpacket(pcap_t *, const u_char *, int);
函数功能:将数据包原样发送到网络中
返回值:int
参数说明:
参数1:所打开的设备
参数2:待发送的数据
参数3:数据块大小
程序中调用示例:
pcap_sendpacket(pcap, (UCHAR*)&arp_, sizeof(arp_));
附上源码:
程序源代码: // OpenDev.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include"iostream" #include "iomanip" #define HAVE_REMOTE #include"pcap.h" #include "packet32.h" #include "ntddndis.h" #include "stdlib.h" #include "memory" #pragma pack(1) //memory alignment #pragma comment(lib,"wpcap.lib") #pragma comment(lib,"Packet.lib") #pragma comment(lib,"ws2_32.lib") using std::cout; using std::endl; using std::cin; using std::setfill; using std::setw; // struct _ARP_HEAD{ u_short hardware_type; //硬件类型 0x0001 u_short protocal_type; //协议类型 0x0800 u_char hardware_addr_len; //硬件地址长度 06 u_char protocal_addr_len; //协议地址长度 04 USHORT operation_field; //操作字段 01 request , 02 response UCHAR source_mac_addr[6]; //源mac地址 will be filled in runtime ULONG source_ip_addr; //源ip地址 localhost UCHAR dest_mac_addr[6]; //目的max地址 00:00:00:00:00:00 ULONG dest_ip_addr; //目的ip地址 }; // struct _ETHER_HEAD{ UCHAR dest_mac_addr[6]; //目的 mac 地址 UCHAR source_mac_addr[6]; //源 mac 地址 USHORT type; //帧类型 }; // struct _ARP{ _ETHER_HEAD eh; _ARP_HEAD ah; char padding[18]; // to make sure the sizeof(BYTES) >= 60 }; // to make an arp protocal void MakeArp(_ARP * _arp, unsigned char* source_mac_addr, unsigned long source_ip_addr, unsigned long dest_ip_addr); void MakeArp(_ARP * _arp, unsigned char* source_mac_addr, unsigned char* dest_mac_addr, unsigned long source_ip_addr, unsigned long dest_ip_addr, USHORT flag); // to get devices' name and do more things in this function void GetDevName(ULONG,ULONG,PUCHAR,USHORT); // to get the local mac addr void GetLocalMac(UCHAR * _u_char, PCHAR _adapter); // to parse the mac addr PUCHAR ParseMac(char * mac); int main(int argc, char* argv[]) { if (argc<1) { return 0; } PUCHAR mac_addr = ParseMac(argv[3]); GetDevName(inet_addr(argv[1]),inet_addr(argv[2]),mac_addr,atoi(argv[4])); free(mac_addr); system("pause"); return 0; } //to parse the mac addr PUCHAR ParseMac(char * mac) { int i = strlen(mac); PUCHAR TMP = (PUCHAR)malloc(i / 2); char tmp[2] = { 0 }; _strlwr(mac); int count = 0; int Counttmp = 0; int changemod = 0; while (count < i) { if (mac[count] >= 'a'&& mac[count] <= 'f') tmp[changemod] = mac[count] - 0x60 + 9; else if (mac[count] >= '0' && mac[count] <= '9') { tmp[changemod] = mac[count] - 0x30; } else break; ++changemod; ++count; if (2 == changemod) { changemod = 0; TMP[Counttmp] = tmp[0] * 16 + tmp[1]; ++Counttmp; } } return TMP; } /** * Print the device info * */ void GetDevName(ULONG source_ip, ULONG dest_ip, PUCHAR dest_mac, USHORT flag) { pcap_if_t * alldevs; void packet_backFUNC(u_char *param, const struct pcap_pkthdr *header, const u_char * pkt_data); int count = 0; char source[PCAP_BUF_SIZE + 1] = { "rcap://\0" }; char error[PCAP_BUF_SIZE + 1] = { 0 }; //print all the device we had found if (pcap_findalldevs_ex(source,NULL,&alldevs,error) == -1) { cout << " Can't find the device ! \n"; return; } else { // this part is to display the info of NIC ,now we don't need it // 由于题目没有要求查看设备信息,所以注释掉这一部分,如果需要查看设备信息,可以打开这部分注释 for (auto d = alldevs; d; d = d->next) { ++count; /*cout << "Number : " << count << endl << "Name :" << d->name << endl << "Description : " << d->description << endl;*/ //for (auto tmp = d->addresses; tmp;tmp=tmp->next) //{ // /*cout << "Address Family : #" << (int)tmp->addr->sa_family << endl << endl;*/ // if (tmp->addr->sa_family == AF_INET) // { // /* cout << "Address Family Name : AF_INET" << endl // << "IP addr : " << inet_ntoa(((struct sockaddr_in*)tmp->addr)->sin_addr) << endl // << "Net mask : " << inet_ntoa(((struct sockaddr_in*)tmp->netmask)->sin_addr) << endl // << "BroadAddr : " << inet_ntoa(((struct sockaddr_in*)tmp->broadaddr)->sin_addr) << endl;*/ // } // else{ // /*cout << "Address Family Name : Unknown\n";*/ // } //} /*cout.fill('-'); cout.width(79); cout << endl << "" << endl << endl;*/ } } if (count == 0) { cout << "No Interface has found ,make sure the WinPcap has installed \n"; } // to choose an interface int ntmp_ = 1; if (ntmp_ <1 || ntmp_ >count) { cout << "The number out of range \n"; pcap_freealldevs(alldevs); return; } //jump to the choice pcap_if_t *tmp_ = alldevs; for (int nNumber = 1; nNumber < ntmp_; nNumber++, tmp_ = tmp_->next); //open the choice auto pcap = pcap_open( tmp_->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, //以混杂模式打开网卡 1000, NULL, error); if (pcap == NULL) { cout << "Error has occured at open the device\n FileName : " << __FILE__ << "\nLine : " << __LINE__ << endl; pcap_freealldevs(alldevs); return; } // get an input of dest IP // to get the mac addr UCHAR macbuff[10] = { 0 }; // "&(tmp_->name)[8]" is the beginning of a device's name with out "rpcap://" so that we can use PacketOpenAdapter successfully GetLocalMac(macbuff, &(tmp_->name)[8]); //create an arp _ARP arp_; MakeArp(&arp_, macbuff, dest_mac, source_ip, dest_ip, flag ); //begin to send pcap_sendpacket(pcap, (UCHAR*)&arp_, sizeof(arp_)); //free the devices list pcap_freealldevs(alldevs); pcap_close(pcap); cout << "ARP has been sent correctly !\n"; } // #define UNDO void packet_backFUNC(u_char *param, const struct pcap_pkthdr *header, const u_char * pkt_data) { // TODO } void MakeArp(_ARP * _arp, unsigned char* source_mac_addr, unsigned long source_ip_addr, unsigned long dest_ip_addr) { // set the ethernet info memset(_arp->eh.dest_mac_addr, 0xff, 6); memcpy(_arp->eh.source_mac_addr, source_mac_addr, 6); _arp->eh.type = htons(0x0806); // set the arphead info _arp->ah.hardware_addr_len = 6; _arp->ah.hardware_type = htons(0x0001); _arp->ah.operation_field = htons(1); _arp->ah.protocal_addr_len = 4; _arp->ah.protocal_type = htons(0x0800); _arp->ah.source_ip_addr = source_ip_addr; memcpy(_arp->ah.source_mac_addr, source_mac_addr, 6); _arp->ah.dest_ip_addr = dest_ip_addr; memset(_arp->ah.dest_mac_addr, 0, 6); //Zero the padding ZeroMemory(_arp->padding, 18); } void MakeArp(_ARP * _arp, unsigned char* source_mac_addr,unsigned char* dest_mac_addr, unsigned long source_ip_addr, unsigned long dest_ip_addr, USHORT flag) { if (flag == 0) { MakeArp(_arp, source_mac_addr, source_ip_addr, dest_ip_addr); return; } else { MakeArp(_arp, source_mac_addr, source_ip_addr, dest_ip_addr); memcpy(_arp->eh.dest_mac_addr, dest_mac_addr, 6); memcpy(_arp->eh.source_mac_addr, source_mac_addr, 6); memcpy(_arp->ah.source_mac_addr, source_mac_addr, 6); memcpy(_arp->ah.dest_mac_addr, dest_mac_addr, 6); _arp->ah.operation_field = htons(2); return; } } // to get the local mac #define ADAPTER_NAME_SIZE 512 void GetLocalMac(UCHAR * _u_char,PCHAR _adapter) { LPADAPTER lpadapter; lpadapter = PacketOpenAdapter(_adapter); if (!lpadapter || (INVALID_HANDLE_VALUE == lpadapter->hFile)) { cout << "Unable to open the adapter,Error Code:" << GetLastError(); return; } PPACKET_OID_DATA poid_data_; poid_data_ = (PPACKET_OID_DATA)malloc(6 + sizeof(PACKET_OID_DATA)); poid_data_->Oid = OID_802_3_CURRENT_ADDRESS; poid_data_->Length = 6; ZeroMemory(poid_data_->Data, 6); auto status = PacketRequest(lpadapter, FALSE, poid_data_); if (status) { memcpy(_u_char, poid_data_->Data, 6); } else { cout << "An error has occured at file : " << __FILE__ << " line : " << __LINE__<<endl; } free(poid_data_); PacketCloseAdapter(lpadapter); }
相关文章推荐
- hdu 4043 2011北京赛区网络赛D 概率+大数 **
- 【Apache学习】httpd2.4 版本下 https配置
- TCP/IP详解学习笔记--TCP连接的建立与终止
- hdu 4041 2011北京赛区网络赛B 搜索 ***
- 一次完整的HTTP请求所经历的7个步骤
- Wireshark查看https的通讯
- Http请求之android-async-http 异步框架请求
- HTTP Header 详解
- HttpContext.Current.User.Identity.Name获得不了登录名
- hdu 4046 2011北京赛区网络赛G 线段树 ***
- TCP连接分组交换状态图显示
- 基于java调用https接口
- 设置HttpSendRequest阻塞时间
- ios网络请求 get——post 区别
- HTTP跨域调用-传入URL就直接返回回来数据
- HttpClient异步调用WEB服务
- C++ http socket 文件上传和下载 FILE写文件失败
- TCP状态转换图详解
- TCP学习(1)--报文段首部格式
- http和socket之长连接和短连接区别