网络编程第三方库——Libnet库(发送)

一、概念

专业的构造和发送网络数据包的开发工具包,是个高层次的API函数库,允许开发者自己构造和发送网络数据包。

头文件:#include<libnet.h>
编译加:-lnet

二、Libnet特点

①隐藏了很多底层细节,省去了很多麻烦:如缓冲区管理、字节流顺序、校验和计算等问题,使开发者把重心放到程序的开发中。
②可以轻松、快捷的构造任何形式的网络数据包,从而开发各种各样的网络程序。
③使用非常广泛,例子著名的软件Ettercap、Firewalk、Snort、Tcpreplay等。
④在1998年就出现了,但那时候还有很多缺陷,比如计算校验和非常繁琐等;
⑤Schiffman对其进行了完善,而且功能更加强大。至此,可以谁Libnet开发包非常完美了,使用人数越来越多。

三、Libnet库的安装

sudo apt-get install libnet-dev

四、开发流程

利用libnet函数库开发应用程序的基本步骤
①数据包内存初始化
②构造数据包
③发送数据
④释放资源

libnet库主要功能
①内存管理
②地址解析
③包处理

内存管理相关函数

①初始化

libnet_t *libnet_init(int injection_type, char *device, char *err_buf);

功能:数据包内存初始化及环境建立

参数:injection_type:构造的类型(LIBNET_LINK,LIBNET_TAW4, LIBNET_LINK_ADV(推荐), LIBNET_RAW4_ADV)
     device:网络接口,如"eth0"或IP地址,亦可为NULL(自动查询搜索)
     err_buf:存放出错的信息

返回值:成功返回一个libnet句柄,失败返回NULL

在这里插入图片描述
②构建数据包
构建UDP报文

libnet_ptag_t libnet_build_udp(u_int16_t sp, u_int16_t dp,
							   u_int16_t len, u_int16_t sum,
							   u_int8_t *payload, u_int32_t payload_s,
							   libnet_t *l, libnet_ptag_t ptag);
功能:构造UDP数据包

参数:sp:源端口号
	dp:目的端口号
	len:UDP包总长度
	sum:校验和,设为0,libnet自动填充
	payload:负载,可设置为NULL
	payload_s:负载长度,或为0
	l:libnet句柄
	ptag:协议标记

返回值:成功返回协议标记;失败返回-1			

构建IPv4数据包

libnet_ptag_t libnet_build_ipv4(u_int16_t ip_len, u_int8_t tos,
						        u_int16_t id, u_int16_t flag,
						        u_int8_t ttl, u_int8_t port,
						        u_int16_t sum, u_int32_t src,
						        u_int32_t dst, u_int8_t *payload,
						        u_int32_t payload_s, libnet_t *l,
						        libnet_ptag_t ptag);
功能:构造一个IPv4数据包

参数:ip_len:ip包总长
     tos:服务类型
     id:id表示
     flag:片偏移
     ttl:生存时间
     prot:上层协议
     sum:校验和,设为0,libnet自动填充
     src:源IP地址
     dst:目的IP地址
     payload:负载,可设置为NULL
     payload_s:负载长度,或为0,
     l:libnet句柄
     ptag:协议标记

返回值:成功返回协议标记;失败返回-1						       						     

构建以太网数据包

libnet_ptag_t libnet_build_ethernet(u_int8_t *dst, u_int8_t *src,
								    u_int16_t type, u_int8_t *payload,
								    u_int32_t payload_s, libnet_t *l,
								    libnet_ptag_t ptag);
功能:构造一个以太网数据包

参数:dst:目的mac
     src:源mac
     type:上层协议类型
     payload:负载,即附带的数据
     payload_s:负载长度
     l:libnet句柄
     ptag:协议标记

返回值:成功返回协议标记;失败返回-1	

③发送帧数据

int libnet_write(libnet_t *l);

功能:发送数据到网络

参数:l:libnet句柄

返回值:失败返回-1,成功返回其他。

④释放资源

void libnet_destroy(libnet_t *l);

功能:释放资源

参数:l:libnet句柄

返回值:

例子:

#include <stdio.h>
#include <string.h>
#include <libnet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
	//1.初始化内存
	libnet_t *lib_handle = libnet_init(LIBNET_LINK_ADV,"enp0s3",NULL);
	
	//获取键盘输入
	char data[128]="";
	printf("请输入数据:\n");
	fgets(data,sizeof(data),stdin);
	data[strlen(data-1)]=0;
	int data_len = strlen(data)+strlen(data)%2;	//将长度变为偶数
	
	//2.构建数据包:从应用层--->链路层
	//构建UDP数据(传输层)
	libnet_ptag_t ptag_udp =libnet_build_udp(8000,9000,8+data_len,0,data,data_len,lib_handle,0);
	//构建IPv4数据(网络层)
	libnet_ptag_t ptag_ip = libnet_build_ipv4(20+8+data_len,0,0,0,128,17,0,inet_addr("192.168.199.208"),inet_addr("192.168.199.233"),NULL,0,lib_handle,0);
	//构建以太网数据包(链路层)
	unsigned char src_mac[6]={0x08,0x00,0x27,0x2d,0x9b,0x84};	//虚拟机mac
	unsigned char dst_mac[6]={0x80,0xc5,0xf2,0xb9,0x8c,0x03};	//windows的mac
	libnet_ptag_t ptag_mac = libnet_build_ethernet(dst_mac,src_mac,0x0800,NULL,0,lib_handle,0);
	
	//3.发送帧数据
	libnet_write(lib_handle);
	
	//4.释放资源
	libnet_destroy(lib_handle);
	
	return 0;
}
### 配置和应用VLAN标签于Socket通信 在网络编程中,当涉及到虚拟局域网(VLAN)时,通常需要通过设置802.1Q VLAN标签来指定流量所属的具体VLAN。对于Linux环境下的C/C++程序而言,在使用原始套接字(Raw Socket)或PF_PACKET类型的套接字进行低层次的数据包捕获与发送操作时可以实现这一点。 为了在数据帧上添加VLAN标记,一种方法是在构建以太网帧时手动插入相应的字段。这涉及到了解IEEE 802.1Q标准定义的格式,并按照此格式构造包含有TPID (Tag Protocol Identifier) 和 TCI (Tag Control Information) 的额外头部信息[^2]。 然而更简便的方式是利用操作系统内核提供的辅助功能——即`setsockopt()`函数配合特定选项完成自动打标工作。具体来说就是调用`setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, ...)`绑定接口之后再通过`vlan_raw_device_bind()`或者借助第三方库如libpcap/libnet简化流程;而对于支持VLAN特性的现代Linux发行版,则可以直接创建带有`.X`后缀表示子接口名称的真实设备并关联至主物理网卡之上,进而使得常规BSD风格的流/数据报套接字也能透明处理带标签的数据单元[^1]。 下面是基于Python的一个简单例子展示怎样利用pyroute2快速建立一个属于某VLAN ID的新逻辑接口: ```python from pyroute2 import IPRoute ip = IPRoute() try: ip.link('add', ifname='eth0.10', kind='vlan', link_index=ip.link_lookup(ifname='eth0')[0], vlan_id=10) finally: ip.close() ``` 上述脚本片段展示了如何在一个名为 eth0 的现有网络接口基础上新增加编号为10号VLAN成员身份对应的虚接口对象 `eth0.10` 。一旦成功执行完毕,后续任何针对这个新命名实体发起的标准socket API请求都将默认携带恰当的802.1q封装头信息参与实际传输过程之中[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值