libnet是一个小型接口函数库,主要用C语言写成,提供了低层网络数据包的构造、处理和发送功能。libnet的开发目的是建立一个简单统一的网络编程接口,以屏蔽不同操作系统底层网络编程的差别,使得程序员将精力集中在解决关键问题上。其主要特点如下:
高层接口:libnet主要用C语言写成。
可移植性:libnet目前可以在Linux、FreeBSD、Solaris、WindowsNT等操作系统上运行,并提供了统一的接口。
数据包构造:libnet提供了一系列的TCP/IP数据报文的构造函数,以方便用户使用。
数据包的处理:libnet提供了一系列辅助函数,利用这些辅助函数,帮助用户简化那些烦琐的事务性的编程工作。
数据包发送:libnet允许用户在两种不同的数据包发送方法中选择。
另外,libnet还允许程序获得对数据包的绝对控制,其中一些是传统的网络程序接口所不能提供的,这也是libnet的魅力之一。
libnet支持TCP/IP协议族中的多种协议,比如其上一个版本libnet1.0支持了10种协议,一些新的协议,比如对IPV6的支持还在开发之中。目前最新版本是1.1.2.1版。
Libnet的开发流程如图1和图2所示。
初始化由libnet_init(intinjection_type,char*device,char*err_buf)完成,injection_type表示构造的类型,device表示网络接口,err_buf用于存放出错的信息。初始化代码的示例如下:
libnet_t*libnet_init(intinjection_type,char*device,char*err_buf); l=libnet_init(LIBNET_LINK,“eth0”,err_buf); if(NULL==l) { fprintf(stderr,“libnet_init():%s”,errbuf); }
初始化①:确定libnet类型,共7种。
LIBNET_LINK:表示构造链路层开始的数据包;
LIBNET_RAW4:表示构造IPV4原始套接字接口类型的数据包;
LIBNET_RAW6:表示构造IPV6原始套接字接口类型的数据包;
LIBNET_LINK_ADV:表示高级模式链路层接口类型;
LIBNET_RAW4_ADV:表示高级模式原始套接字接口IPv4类型;
LIBNET_RAW6_ADV:表示高级模式原始套接字接口IPv4类型;
LIBNET_ADV_MASK:用来检测是否是高级模式。
初始化②:确定网络接口。
数据包发送的接口,一种是由自己指定,可以是网络接口的名字,如以太网接口eth0等,也可以是IP地址;一种是由libnet自动查询搜索,只要在函数libnet_init()的参数device赋值null即可,此时libnet会从系统中搜索可用的网络接口。
初始化③:获取libnet的句柄,执行完后返回一个libnet句柄,这个句柄里面包含了重要的信息。
#defineLIBNET_LINK0x00 #defineLIBNET_RAW40x01 #defineLIBNET_RAW60x02 #defineLIBNET_LINK_ADV0x08 #defineLIBNET_RAW4_ADV0x09 #defineLIBNET_RAW6_ADV0x0a #defineLIBNET_ADV_MASK0x08
地址转换可以使用如下的函数来实现。
u_int32_tlibnet_name2addr4(libnet_t*l,char*host_name,u_int8_tuse_name); char*libnet_addr2name4(u_int32_taddress,u_int8_tuse_name);
构造数据包构造:一个数据包就是构造一系列协议块。
数据包检测:数据包的检测最主要的是计算校验和,如果不想自己计算校验和,只需要将校验和的参数赋值为0即可,libnet会自动计算校验和。
数据包发送:非常简单,只要由函数libnet_write()来完成即可。
具体构造如ARP数据包的流程如图3所示。
完整的实现代码如下:
#if(HAVE_CONFIG_H) #if((_WIN32)!(__CYGWIN__)) #include../include/win32/config.h #else #include../include/config.h #endif #endif #include./libnet_test.h int main(intargc,char*argv[]) { intc; uint32_ti; libnet_t*l; libnet_ptag_tt; char*device=NULL; uint8_t*packet; uint32_tpacket_s; charerrbuf[LIBNET_ERRBUF_SIZE]; printf(libnet1.1packetshaping:ARP[link--autobuildingethernet]\n); if(argc>1) { device=argv[1]; } l=libnet_init( LIBNET_LINK_ADV, /*injectiontype*/ /*networkinterface*/ /*errbuf*/ device, errbuf); if(l==NULL) { fprintf(stderr,%s,errbuf); exit(EXIT_FAILURE); } else i=libnet_get_ipaddr4(l); t=libnet_build_arp( ARPHRD_ETHER, /*hardwareaddr*/ /*protocoladdr*/ ETHERTYPE_IP, 6, /*hardwareaddrsize*/ /*protocoladdrsize*/ /*operationtype*/ /*senderhardwareaddr*/ /*senderprotocoladdr*/ /*targethardwareaddr*/ /*targetprotocoladdr*/ /*payload*/ 4, ARPOP_REPLY, enet_src, (uint8_t*)i, enet_dst, (uint8_t*)i, NULL, 0, /*payloadsize*/ l, /*libnetcontext*/ 0); /*libnetid*/ if(t==-1) { fprintf(stderr,CantbuildARPheader:%s\n,libnet_geterror(l)); gotobad; } t=libnet_autobuild_ethernet( enet_dst, /*ethernetdestination*/ /*protocoltype*/ ETHERTYPE_ARP, l); /*libnethandle*/ if(t==-1) { fprintf(stderr,Cantbuildethernetheader:%s\n, libnet_geterror(l)); gotobad; } if(libnet_adv_cull_packet(l,packet,packet_s)==-1) { fprintf(stderr,%s,libnet_geterror(l)); } else { fprintf(stderr,packetsize:%d\n,packet_s); libnet_adv_free_packet(l,packet); } c=libnet_write(l); if(c==-1) { fprintf(stderr,Writeerror:%s\n,libnet_geterror(l)); gotobad; } else { fprintf(stderr,Wrote%dbyteARPpacketfromcontext\%s\; checkthewire.\n,c,libnet_cq_getlabel(l)); } libnet_destroy(l); return(EXIT_SUCCESS); bad: } libnet_destroy(l); return(EXIT_FAILURE);