学习文档
这里我们直接进入正题吧,关于 Winpcap 的基础知识讲解这里就不再赘述了。在这里给大家提供一些学习网址 Winpcap 网络编程及通信教程Winpcap 中文技术文档
学习内容
- 获取设备列表
- 获取已安装设备的高级信息
- 打开适配器并捕获数据包
- 不用回调方法捕获数据包
- 过滤数据包
- 分析数据包
- 处理脱机堆文件
- 发送数据包
- 收集并统计网络流量
这些内容,在上述两个链接中均已经有了比较详细的讲解,希望对大家有帮助。
两台主机通信实战
完成两台主机之间的数据通信(数据链路层)
- 仿真 ARP 协议获得网段内主机的 MAC 表
- 使用帧完成两台主机的通信(Hello! I’m …)
首先我们要理解 ARP 是干嘛的,ARP 主要作用就是通过 IP 地址来获取 MAC 地址。那么怎样获取呢?本机向局域网内主机发送 ARP 包,ARP 包内包含了目的 IP,源 IP,目的 MAC,源 MAC,其中目的 MAC 地址为广播地址,FF-FF-FF-FF-FF-FF, 即向局域网内所有主机发送一个 ARP 请求,那么其他主机收到这个请求之后则会向请求来源返回一个数据包。在这个返回的数据包中包含了自身的 MAC 地址。那么本机收到这些返回的数据包进行解析之后便会得到局域网内所有主机的 MAC 地址了.. 编程开始: 新建一个 C++ 项目,配好环境,引入 Winpcap 相关的库,这些不再赘述。 头文件引入
1 |
|
在 main 函数中首先声明一系列变量如下
1 |
char *ip_addr; //IP地址 |
为这三个变量分配地址空间
1 |
ip_addr = (char *) malloc(sizeof(char) * 16); //申请内存存放IP地址 |
接下来就是烂大街的程序,获取适配器列表并选中相应的适配器,注释已经在代码中了,如果还有不明白的请参照前几次的讲解。
1 |
//获取本地适配器列表 |
上述代码中需要另外声明的有:
1 |
pcap_if_t * alldevs; //所有网络适配器 |
1 |
char *iptos(u_long in); //u_long即为 unsigned long |
1 |
/* 将数字类型的IP地址转换成字符串类型的 */ |
到此程序应该会编译通过,可以试着编译一下运行。 GO ON… 接下来我们首先要用 ifget 方法获取自身的 IP 和子网掩码 函数声明:
1 |
void ifget(pcap_if_t *d, char *ip_addr, char *ip_netmask); |
1 |
//获取IP和子网掩码赋值为ip_addr和ip_netmask |
main 函数继续写,如下调用,之前声明的 ip_addr 和 ip_netmask 就已经被赋值了
1 |
ifget(d, ip_addr, ip_netmask); //获取所选网卡的基本信息--掩码--IP地址 |
到现在我们已经获取到了本机的 IP 和子网掩码,下一步发送一个 ARP 请求来获取自身的 MAC 地址 这个 ARP 请求的源 IP 地址就随便指定了,就相当于你构造了一个外来的 ARP 请求,本机捕获到了请求,然后发送回应给对方的数据包也被本机捕获到了并解析出来了。解析了自己发出去的数据包而已。 那么我们就声明一个函数并实现:
1 |
int GetSelfMac(pcap_t *adhandle, const char *ip_addr, unsigned char *ip_mac); |
1 |
// 获取自己主机的MAC地址 |
其中我们需要定义一下常量如下
1 |
|
另外发送 ARP 请求少不了帧头和 ARP 头的结构,我们需要声明出来,另外我们构建发送包需要再声明两个结构体 sparam 和 gparam
1 |
//帧头部结构体,共14字节 |
到现在代码也是完整可以运行的,如果有问题请检查上述代码完整性和位置。 可能出现的 BUG: 只显示 ARP 发送成功,没有接受到并解析打印。可能的原因是帧构造有问题,字节没有对齐,有偏差,像 #define 一样 写入如下代码:
1 |
|
GO ON.. 获取到了自身的 MAC 地址之后,就可以在本机上构建 ARP 广播请求,向局域网内的所有主机发送 ARP 请求,得到回应之后解析回应的数据包并进行解析,得到对方的 MAC 地址。在这里我们需要开启两个线程,一个用来发送一个用来接收。好,我们继续.. 先声明两个线程
1 |
HANDLE sendthread; //发送ARP包线程 |
在 main 方法中继续写,对 sp 和 gp 两个 ARP 请求所需要的结构体进行赋值。赋值什么?就是你之前用 ifget 获取来的 IP 地址和子网掩码以及用 getSelfMac 获取来的 MAC 地址。
1 |
sp.adhandle = adhandle; |
接下来直接创建两个线程,一个是发送一个接受,分别调用两个方法。
1 |
sendthread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendArpPacket, |
那么发送数据包的方法和接收解析数据包的方法怎样实现呢? 发送数据包,发送数据包先对结构体数据进行赋值,就像 getSelfMac 方法一样,然后声明了一个 buffer 用来存储每一个字节内容。 利用 memset 方法对 buffer 进行赋值。再利用一个 for 循环对 255 个主机进行发送,指定他们的 IP 地址。另外定义了一个 flag, 当发送成功之后将 flag 设置为 1
1 |
/* 向局域网内所有可能的IP地址发送ARP请求包线程 */ |
注:此函数和 flag 变量在前面别忘了声明一下… 然后是接收数据包并打印 MAC 地址:
1 |
/* 分析截留的数据包获取活动的主机IP地址 */ |
以上暂告一段落,通过整合以上代码,我们可以得到如下运行结果:
1 |
-------------------------------------------------- |
接下来我们让用户输入要发送的 IP 地址和要发送的数据
1 |
u_int ip1,ip2,ip3,ip4; |
声明一下 TcpData
1 |
char TcpData[20]; //发送内容 |
接下来就是重头戏了,需要声明各种结构体,我们发送的是 TCP 数据,这样,TCP 的 TcpData 就作为真正的内容,然后在前面加上 TCP 头,IP 头,帧头,还有校验和要正确。 最后构成一个完整的帧,那么另外声明的结构体如下,前面代码声明过的帧头部结构体就去掉了。
1 |
//IP地址格式 |
继续 main 函数中对各种结构体的数据进行初始化赋值,并计算校验和。
1 |
//结构体初始化为0序列 |
校验和方法如下:
1 |
//获得校验和的方法 |
记得在声明一下这个方法。如果放在 main 函数前当然就不用声明啦。 另外需要声明的变量有
1 |
struct EthernetHeader ethernet; //以太网帧头 |
1 |
unsigned char SendBuffer[200]; //发送队列 |
接下来的运行结果:
1 |
获取MAC地址完毕,请输 |
截图如下: 好啦,发送帧到此就告一段落啦!如果有疑问请留言。 帧的接收很简单,直接贴源码如下:
1 |
|
运行截图如下
Thank You 如有问题,欢迎留言~
来源:https://cuiqingcai.com/1918.html