libnetlibpcap包传输实践

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

需求对一个特定的文件进行分片发送,构造数据包,发送数据包,接收数据包并提取有效数据,对数据组合还原为原文件。设计当前,基于socket的网络编程已成为当今不可替代的编程方法,它将网络通讯当作文件描述符进行处理,把对这个“网络文件”(即socket套接字)的操作抽象成一种类似于文件操作的方式进行。从实现细节上,这种工作方式根据TCP/IP的网络通讯模型,封装了一系列的实现,使得我们只需要使用一个指定的参数,就可以实现在基于所需协议的数据的发送和接收。但是,如果我们对那些系统自动给我们做的工作感兴趣,希望与发送的数据作“面对面”的接触,根据需求,传统的socket只能实现传输层之上的数据传输,不能自己构造数据包,而且这里需要更底层的操作,比如网络层和数据链路层,故不可用。方案一:Libnet+libpcap这个方案基于C语言实现,对于一个特定的文件,得到其HEX数据,根据需求分成若干个部分,前面每个部分大小一致,剩余作为最后一个部分,将这个数据分别利用libnet组包发送包,利用libpcap抓包解析包,得到后取其有效数据,也就是HEX数据,对其组装,得到最后的文件,整个过程结束。libnetlibnet是UNIX系统同台上网络安全工具开发的重要的库,它和libpcap、libnids一起,给网络安全工具的开发人员提供了一组丰富而且完全的武器,使之得以很方便地编写出结构化强、健壮性好、可移植性高等特点的程序。libnet提供一系列的接口函数,实现和封装了数据包的构造和发送过程。利用它可以亲自构造从应用层到链路层的各层协议的数据包头,并将这些包头与有效数据有序地组合在一起发送出去。当然,它也是基于tcp/ip协议族模型的。利用libnet函数库开发应用程序的基本步骤非常简单:1、数据包内存初始化;2、构造数据包;3、发送数据;4、释放资源;libnet提供的接口函数按其作用可分为四类:*内存管理(分配和释放)函数*地址解析函数*数据包构造函数*数据包发送函数接口函数及其功能以下分别列出这些接口函数及其功能内存管理函数单数据包内存初始化:intlibnet_init_packet(u_shortpacket_size,u_char**buf);单数据包内存释放:voidlibnet_destroy_packet(u_char**buf);多数据包内存初始化:intlibnet_init_packet_arena(structlibnet_arena**arena,u_shortpacket_num,u_shortpacket_size);访问多数据包内存中的下一个数据包:u_char*libnet_next_packet_from_arena(structlibnet_arena**arena,u_shortpacket_size);多数据包内存释放:voidlibnet_destroy_packet_arena(structlibnet_arena**arena);地址解析函数解析主机名:u_char*libnet_host_lookup(u_longip,u_shortuse_name);解析主机名(可重入函数):voidlibnet_host_lookup_r(u_longip,u_shortuse_name,u_char*buf);域名解析:u_longlibnet_name_resolve(u_char*ip,u_shortuse_name);获取接口设备IP地址:u_longlibnet_get_ipaddr(structlibnet_link_int*l,constu_char*device,constu_char*ebuf);获取接口设备硬件地址:structether_addr*libnet_get_hwaddr(structlibnet_link_int*l,constu_char*device,constu_char*ebuf);数据包构造函数(数据包类型多样,这里太多,列几个主要的)ARP协议数据包:intlibnet_build_arp(u_shorthrdw,u_shortprot,u_shorth_len,u_shortp_len,u_shortop,u_char*s_ha,u_char*s_pa,u_char*t_ha,u_char*t_pa,constu_char*payload,intpayload_len,u_char*packet_buf);以太网协议数据包:intlibnet_build_ethernet(u_char*daddr,u_char*saddr,u_shortid,constu_char*payload,intpayload_len,u_char*packet_buf);IP协议数据包:intlibnet_build_ip(u_shortlen,u_chartos,u_shortip_id,u_shortfrag,u_charttl,u_charprotocol,u_longsaddr,u_longdaddr,constu_char*payload,intpayload_len,u_char*packet_buf);TCP协议数据包:intlibnet_build_tcp(u_shortth_sport,u_shortth_dport,u_longth_seq,u_longth_ack,u_charth_flags,u_shortth_win,u_shortth_urg,constu_char*payload,intpayload_len,u_char*packet_buf);UDP协议数据包:intlibnet_build_udp(u_shortsport,u_shortdport,constu_char*payload,intpayload_len,u_char*packet_buf);IP协议数据包选项:intlibnet_insert_ipo(structipoption*opt,u_charopt_len,u_char*packet_buf);TCP协议数据包选项:intlibnet_insert_tcpo(structtcpoption*opt,u_charopt_len,u_char*packet_buf);数据包发送函数打开rawsocket:intlibnet_open_raw_sock(intprotocol);关闭rawsocket:intlibnet_close_raw_sock(intsocket);选择接口设备:intlibnet_select_device(structsockaddr_in*sin,u_char**device,u_char*ebuf);打开链路层接口设备:structlibnet_link_int*libnet_open_link_interface(char*device,char*ebuf);关闭链路层接口设备:intlibnet_close_link_interface(structlibnet_link_int*l);发送IP数据包:intlibnet_write_ip(intsocket,u_char*packet,intpacket_size);发送链路层数据包:intlibnet_write_link_layer(structlibnet_link_int*l,constu_char*device,u_char*packet,intpacket_size);检验和计算:intlibnet_do_checksum(u_char*packet,intprotocol,intpacket_size);相关的支持函数随机数种子生成器:intlibnet_seed_prand();获取随机数:u_longlibnet_get_prand(intmodulus);16进制数据输出:voidlibnet_hex_dump(u_char*buf,intlen,intswap,FILE*stream);端口列表链初始化:intlibnet_plist_chain_new(structlibnet_plist_chain**plist,char*token_list);获取端口列表链的下一项(端口范围):intlibnet_plist_chain_next_pair(structlibnet_plist_chain*plist,u_short*bport,u_short*eport);端口列表链输出显示:intlibnet_plist_chain_dump(structlibnet_plist_chain*plist);获取端口列表链:u_char*libnet_plist_chain_dump_string(structlibnet_plist_chain*plist);端口列表链内存释放:voidlibnet_plist_chain_free(structlibnet_plist_chain*plist);libpcaplibpcap是一个网络数据包捕获函数库,功能非常强大,Linux下著名的tcpdump就是以它为基础的。如何使用libpcap:首先要使用libpcap,我们必须包含pcap.h头文件,可以在/usr/local/include/pcap/pcap.h找到,其中包含了每个类型定义的详细说明。1.获取网络接口首先我们需要获取监听的网络接口:我们可以手动指定或让libpcap自动选择,先介绍如何让libpcap自动选择:char*pcap_lookupdev(char*errbuf)上面这个函数返回第一个合适的网络接口的字符串指针,如果出错,则errbuf存放出错信息字符串,errbuf至少应该是PCAP_ERRBUF_SIZE个字节长度的。注意,很多libpcap函数都有这个参数。pcap_lookupdev()一般可以在跨平台的,且各个平台上的网络接口名称都不相同的情况下使用。如果我们手动指定要监听的网络接口,则这一步跳过,我们在第二步中将要监听的网络接口字符串硬编码在pcap_open_live里。2.释放网络接口在操作为网络接口后,我们应该要释放它:voidpcap_close(pcap_t*p)该函数用于关闭pcap_open_live()获取的pcap_t的网络接口对象并释放相关资源。3.打开网络接口获取网络接口后,我们需要打开它:pcap_t*pcap_open_live(constchar*device,intsnaplen,intpromisc,intto_ms,char*errbuf)上面这个函数会返回指定接口的pcap_t类型指针,后面的所有操作都要使用这个指针。第一个参数是第一步获取的网络接口字符串,可以直接使用硬编码。第二个参数是对于每个数据包,从开头要抓多少个字节,我们可以设置这个值来只抓每个数据包的头部,而不关心具体的内容。典型的以太网帧长度是1518字节,但其他的某些协议的数据包会更长一点,但任何一个协议的一个数据包长度都必然小于65535个字节。第三个参数指定是否打开混杂模式(PromiscuousMode),0表示非混杂模式,任何其他值表示混合模式。如果要打开混杂模式,那么网卡必须也要打开混杂模式,可以使用如下的命令打开eth0混杂模式:ifconfigeth0promisc第四个参数指定需要等待的毫秒数,超过这个数值后,第3步获取数据包的这几个函数就会立即返回。0表示一直等待直到有数据包到来。第五个参数是存放出错信息的数组。4.获取数据包打开网络接口后就已经开始监听了,那如何知道收到了数据包呢?有下面3种方法:a)u_char*pcap_next(pcap_t*p,structpcap_pkthdr*h)如果返回值为NULL,表示没有抓到包第一个参数是第2步返回的pcap_t类型的指针第二个参数是保存收到的第一个数据包的pcap_pkthdr类型的指针pcap_pk

1 / 14
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功