http://www.jiaojiaoni.com/archives/250.html
Libnet是一个高层API,使用C语言实现的,为应用程序设计人员提供了底层的网络数据报的构造处理和发送等功能接口。
Libnet提供的接口函数主要用于实现和封装了数据包的构造和发送过程。
首先是对libnet包的文件结构的介绍
libnet-functions.h 该文件是对libnet中接口的声明文件,所有的接口都在这里面。程序员可以参看这个文件里的结构进行程序开发。
libnet-structures.h 该文件中定义的都是libnet的核心的数据结构所有的核心的struct都是定义在这里的
libnet-types.h 该文件是空的里面可以自己定义一些数据类型
开发框架层流程图如下所示:
利用libnet函数库开发应用程序的基本步骤很简单:
1 数据包内存初始化
2 构造数据包
3 发送数据
4 释放资源
其中构造数据包的过程是个复杂的过程,中间设计到很多libnet_build的过程
下面是对libnet开发应用程序的流程的总结:
一般情况下,会先从libnet_init开始执行,libnet_init首先开启系统的网络功能:
在linux下,它会验证是否具有超级用户权限,也就是说低级权限的用户不能使用。
之后分配一块内存区域建立libnet_t结构,在简单的初始化后,根据传入的发送类
型参数,进行相应的操作:如果是基于链路层的发送方式(LIBNET_LINK或者
LIBNET_LINK_ADV),则会向操作系统申请设备,并开启底层的socket服务。如果是
基于IP层的发送方式,则开始该层的socket服务。
初始化准备工作完成后,就进入了建包的工作,建包工作实际表现为建立一系列的
协议包头,程序员需要自顶向下的顺序建立协议包头,而要发送的正文数据往往被
作为协议包头的有效载荷被加载,此外,有些协议可能具有可选数据项,这一部分
被libnet独立出来,由一个独立的libnet_pblock_t来负责,libnet同时也为此提
供相应的功能函数,命名一般为:
Libnet_build_*_options(),在这种情况下,libnet会自动调整这些协议块在链表
中的位置,使payload数据块在前面,之间是options块,随后跟随该层协议的固定包头。
接下来就是数据的写操作了,libnet_write()函数会执行对数据的写操作,这样链
表中的数据被按顺序的拷贝到一个大的缓冲区内,拷贝虽然是按照从高层到底层协
议的顺序进行的,但是却是从缓冲的后部向前部拷贝的。
在一切工作完成后,程序员只需要简单的调用libnet_destroy()函数关闭使用的网
络通讯设备即可,释放占用的内存。
下面是对上述图的讲解:
初始化部分:
Libnet_t* libnet_init(int injection_type,char* device,char* err_buf)
参数解释
injection_type表示构造的类型
device 表示网络接口通常就是eth0 eth1等
err_buf 表示存放出错的信息
例子:
L=libnet_init(LIBNET_LINK,”eth0”,err_buf);
If(NULL==L){
Printf(“初始化错误!错误代码:%s\n”,errbuf);
}
Injection_type表示构造的类型:
LIBNET_LINK 表示构造数据链路层开始的数据包
LIBNET_RAW4 表示构造IPV4原始套接字接口类型的数据包
LIBNET_RAW6 表示构造IPV6原始套接字接口类型的数据包
LIBNET_LINK_ADV 表示高级模式链路层接口类型
LIBNET_RAW4_ADV 表示高级模式原始套接字接口IPv4类型
LIBNET_RAW6_ADV 表示高级模式原始套接字接口IPv6类型
LIBNET_ADV_MASK 用来检测是否是高级模式
device 表示网络接口
网络接口就是数据包发送的接口,分两种:
一种是自己指定的,可以是网络接口的名字,如以太网接口”eth0”等,也可以是IP地址
一种是libnet自动查询搜索的,此时需要在函数libnet_init()参数device赋值NULL就可,此时libnet会从系统中搜索可以使用的网络接口。
Libnet_init函数返回值
Libnet_init函数返回值表示句柄,相当于对应的类型,返回值如下所示:
#define LIBNET_LINK 0x00
#define LIBNET_RAW4 0x01
#define LIBNET_RAW6 0x02
#define LIBNET_LINK_ADV 0x08
#define LIBNET_RAW$_ADV 0x09
#define LIBNET_RAW6_ADV 0x0a
#define LIBNET_ADV_MASK 0x0b
构造数据包
构造一个数据包其实就是构造一系列协议块
LibNet常用函数总结
Libnet常用的函数包括:内存管理函数地址解析函数数据包构造函数数据包发送函数辅助函数等。
内存管理函数
1 单数据包内存初始化以及环境建立函数
libnet_t * libnet_init(int injection_type, const char *device, char *err_buf);
2 资源释放函数
Void libnet_destroy(libnet_t *l);
地址解析函数
地址解析:
char *libnet_addr2name4(u_int32_t in, u_int8_t use_name);
libnet_name2addr4(libnet_t *l, char *host_name, u_int8_t use_name);
struct libnet_in6_addr libnet_name2addr6(libnet_t *l, char *host_name, u_int8_t use_name);
void libnet_addr2name6_r(struct libnet_in6_addr addr, u_int8_t use_name,char *host_name, int host_name_len);
获取接口设备的IP地址
u_int32_t libnet_get_ipaddr4(libnet_t *l);
struct libnet_in6_addr libnet_get_ipaddr6(libnet_t *l);
获取接口设备硬件地址
struct libnet_ether_addr *libnet_get_hwaddr(libnet_t *l);
数据包构造函数
此类函数很多,都是以下面开头的文件libnet_build_*()
数据包发送函数
int libnet_write(libnet_t *l);
辅助函数
随机数产生:
随机数种子:int libnet_seed_prand(libnet_t* l)
随机数产生:u_int32_t libnet_get_prand(int mod)
端口列表链初始化:
int libnet_plist_chain_new(libnet_t *l, libnet_plist_t **plist, char *token_list);
获取端口列表链的下一项(端口范围):
int libnet_plist_chain_next_pair(libnet_plist_t *plist, u_int16_t *bport, u_int16_t *eport);
端口列表链输出显示:
int libnet_plist_chain_dump(libnet_plist_t *plist);
获取端口列表链:
char *libnet_plist_chain_dump_string(libnet_plist_t *plist);
端口列表链内存释放:
int libnet_plist_chain_free(libnet_plist_t *plist);