【计网 从头自己构建协议】一、libpcap 介绍 & 手撕以太网帧

上一篇:IndexError: list index out of range
下一篇:[【计网 从头自己构建协议】二、收发 ARP 请求帧与响应帧]

介绍

理论的学习总是枯燥的,想要加深对理论的理解,最好的方法就是自己实践一遍。

想要亲手实现各种协议,就必须能够接触底层 API。可惜的是,底层的 API 要么是在驱动里,要么是在系统里,都不对外开放,一般只能接触到运输层的 TCP/UDP。我们必须借助第三方库才能实现对底层操控。

libpcap 就是这样一个库,它帮我们实现了底层驱动,并将控制权向上开放,提供了发送和监听数据包的功能。著名的网络分析工具 Wireshark 就是基于这个库实现的。

libpcap 是 Linux 上的库,对应的 Windows 版本叫做 winpcap,不过这个库已经停止开发了,只支持到 Windows 8,没法运行在 Windows 10 上。npcap 在 winpcap 的基础上继续开发,添加了对新版 Windows 的支持和其他的功能。

我们下面就使用 npcap 这个库。

安装

推荐你直接安装 Wireshark,在安装 Wireshark 的同时会一并安装 npcap。所以如果你已经装了 Wireshark ,就不需要再装 npcap 本体了。

除了本体之外,我们还需要开发用的头文件和库文件
npcap 官网下载页面,找到“Downloading and Installing Npcap Free Edition”,把 installer(如果你没装 Wireshark) 和 SDK 都下载下来。

installer 是 npcap 本体,直接双击,一路 next 即可。
SDK 是个压缩包,找个地方解压即可。路径最好要短,不要有中文。推荐专门新建一个文件夹“SDK”来放开发包。
例如“D:\SDK\npcap-sdk-1.13”

配置

Visual Studio

先确保项目配置是 x64 的,如果不是,先切换到 x64 再继续下面的步骤。
工具栏

打开菜单栏 项目 -> XXX 属性,后面的设置都在这里面进行。
C/C++ -> 常规,右边的附加包含目录,添加一条记录 npcap-sdk-1.13\Include。(自行把路径补充完整)
连接器 -> 常规,右边的附加库目录,添加一条记录 npcap-sdk-1.13\Lib\x64。(自行把路径补充完整)
链接器 -> 输入,右边的附加依赖项,在最前面加上 Ws2_32.lib;wpcap.lib;
链接器 -> 输入,右边的延迟加载的 DLL,填入 wpcap.dll

一些前置知识

由于之后我们要经常要在比特和字节之间转换,为了方便,后面不用 charintlong,而用 int8_tint16_tint32_t。其中 int 后面的数字表示比特长度。比如 int8_t 长 8 比特,也就是 1 字节。
需要先 #include <inttypes.h> 才能使用。

此外,数据在内容中的储存分大小端
例如 0x0800 这个数字,长 2 字节,以 1 字节为单位分割,结果是 0x08 0x00。
但是计算机内存中不一定是这样储存的,可能是 0x08 0x00,也可能是 0x00 0x08。就好像以前中文的书写顺序是从右往左,而现在是从左往右,如果看的顺序不对,什么都读不出来。

解决方法是统一网络使用的字节顺序,并额外再写几个函数在转换本地机器字节顺序和网络字节顺序之间转换。

htonl() //"Host to Network Long"
ntohl() //"Network to Host Long"
htons() //"Host to Network Short"
ntohs() //"Network to Host Short"   

h 代表 “host 主机”,n 代表 “network 网络”,to 代表“到”,l 代表“long”类型,s代表“short”类型。
例如 htons() 就是把主机字节序转换为网络字节序,传入的参数是 short 类型。

发送数据

发送数据包用的是 int pcap_sendpacket(pcap_t *p, const u_char *buf, int size); 这个函数。
数据包将会直接原封不动地发送到数据链路层上去,也就是说,我们需要自行构造各种协议的头

构造以太网帧

先从以太网开始。

在发送数据之前,我们得自己起一个函数来帮助我们构造以太网头。
至于以太网帧的格式是什么,自己去翻书
可以参考 Wireshark 的 Wiki 页面 或者 维基百科,直接看 packet format 部分即可。

适配器已经帮我们搞好了帧开始之前 010101… 时钟同步信号、帧开始处的定界符、帧结束处的 FCS 帧检验序列,我们只需要搞定核心部分即可。

int make_ethernet_packet(
	uint8_t target_address[6], // 目的 MAC 地址
	uint8_t source_address[6], // 源 MAC 地址
	int16_t ethertype, // 以太网类型(DIX Ethernet II)/帧长(IEEE 802.3)
	uint8_t *payload, // 数据部分
	size_t payload_length, // 数据长度(比特数)
	uint8_t **data, // 返回值:以太网帧。由调用者释放内存。
	size_t *data_length // 返回值:以太网帧长度(字节数)
)
{
   
   
	// 计算总长度并分配内存
	*data_length = 6 + 6 + 2 + payload_length;

	// 最大帧长 1500-4 字节
	if (*data_length > 1496)
		return -2;

	// 最小帧长 64-4(FCS长度)-6-6-2(头长度)=46 字节
	// 不够要填充额外数据
	if (*data_length < 46)
	{
   
   
		int8_t *new_payload = calloc(60, sizeof(int8_t));
		memcpy(new_payload, payload, payload_length);
		// 覆盖掉原始 payload
		payload = new_payload;
		payload_length = 46;
		// 重新计算 data_length
		*data_length = 6 + 6 + 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值