typedef struct ip_header{
u_char ver_ihl; // 4 bit的版本信息 + 4 bits的头长 u_char tos; // TOS类型 u_short tlen; // 总长度 u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) u_char ttl; // 生存期
u_char proto; // 后面的协议信息 u_short crc; // 校验和 ip_address saddr; // 源IP ip_address daddr; // 目的IP u_int op_pad; // Option + Padding }ip_header;
/* UDP header*/
typedef struct udp_header{ u_short sport; // Source port u_short dport; // Destination port u_short len; // Datagram length u_short crc; // Checksum }udp_header;
/* 定义处理包的函数 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); main() {
pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE]; u_int netmask;
char packet_filter[] = \ struct bpf_program fcode;
/* Retrieve the device list */
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
fprintf(stderr,\ exit(1); }
/* Print the list */
for(d=alldevs; d; d=d->next) {
printf(\ if (d->description)
printf(\ else
printf(\ }
if(i==0) {
printf(\ return -1; }
printf(\ scanf(\
if(inum < 1 || inum > i) {
printf(\ /* Free the device list */ pcap_freealldevs(alldevs); return -1; }
/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/* Open the adapter */
if ( (adhandle= pcap_open_live(d->name, // name of the device 65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on
all the MACs.
1, // promiscuous mode 1000, // read timeout errbuf // error buffer ) ) == NULL) {
fprintf(stderr,\ /* Free the device list */
pcap_freealldevs(alldevs); return -1; }
/* Check the link layer. We support only Ethernet for simplicity. */ if(pcap_datalink(adhandle) != DLT_EN10MB) {
fprintf(stderr,\ /* Free the device list */ pcap_freealldevs(alldevs); return -1; }
if(d->addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; else
/* If the interface is without addresses we suppose to be in a C class network */ netmask=0xffffff;
//compile the filter
if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ){ fprintf(stderr,\ /* Free the device list */ pcap_freealldevs(alldevs); return -1; }
//set the filter
if(pcap_setfilter(adhandle, &fcode)<0){ fprintf(stderr,\ /* Free the device list */ pcap_freealldevs(alldevs); return -1; }
printf(\
/* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(alldevs);
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0; }
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
struct tm *ltime; char timestr[16]; ip_header *ih; udp_header *uh; u_int ip_len; u_short sport,dport;
/* convert the timestamp to readable format */ ltime=localtime(&header->ts.tv_sec);
strftime( timestr, sizeof timestr, \
/* print timestamp and length of the packet */
printf(\
/* 找到IP头的位置 */ ih = (ip_header *) (pkt_data + 14); //14为以太头的长度
/* 找到UDP的位置 */ ip_len = (ih->ver_ihl & 0xf) * 4;
uh = (udp_header *) ((u_char*)ih + ip_len);
/* 将端口信息从网络型转变为主机顺序 */ sport = ntohs( uh->sport ); dport = ntohs( uh->dport );
/* print ip addresses and udp ports */
printf(\ ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, sport,
ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4,
dport); }
首先我门设置UDP过滤,用这种方法我们确保packet_handler()只接受到基于IPV4的UDP数据。我们同样定义了
两个数据结构来描述IP 和UDP的头部信息,packet_handler()用这两个结构来定位头部的各种字段。 packet_handler()虽然只是限于处理一些UDP数据但却显示了复杂的嗅探器如tcpdump/WinDump的工作原理。
首先我们对MAC地址的头部并不感兴趣所以我们跳过它。不过在开始捕获之前我们用pcap_datalink()来检查MAC
层,所以以上的程序只能够工作在Ethernet networks上,再次我们确保MAC头为14 bytes。
MAC头之后是IP头,我们从中提取出了目的地址。IP之后是UDP,在确定UDP的位置时有点复杂,因为IP的长度以
为版本的不同而不同,所以我们用头长字段来定位UDP,一旦 我们确定了UDP的起始位置,我们就可以解析出原
和目的端口。
下面是我们打印出来的一些结果:
1. {A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter) Enter the interface number (1-2):1
listening on Xircom CardBus Ethernet 10/100 Adapter... 16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53 16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682 16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53
上面每一行都显示出不同的数据包的内容.
循序渐进学习使用WINPCAP(七) ----处理脱机的堆文件
通过以前的学习我门已经熟悉了从网卡上捕获数据包,现在我门将学习如何处理数据包。WINPCAP为我们提供了很多API来将流经网络的数据包保存到一个堆文件并读取堆的内容。这一节将讲述如何使用所有的这些API。
这种文件的格式很简单,但包含了所捕获的数据报的二进制内容,这种文件格式也是很多网络工具的标准如WinDump, Ethereal 还有 Snort等.
关于如何将数据包保存到文件: