现在,我们可以捕获并过滤网络流量了,那就简单协议个程序分析网络数据包。
这里我们只是解析所捕获数据包的首部,打印一些数据包首部的信息。我们以UDP为例,因为UDP比较简单。
首先,应该介绍下网络数据包的格式。网络中的数据包每经过一个层次都会加上那个层的报头来标注一些重要的信息。捕获到的数据包首先有个mac报头,14字节,包含6字节目的mac地址、6字节源mac地址,和2字节上一层协议。这里我们不关注mac报头,所以省略。
接下来是IP数据包,包的格式如下图:
IP数据包有20字节的报头,报头格式如下图:
WinPcap没有给出一个保存IP报头信息的结构体,所以需要我们自己定义。下面是IP报头的定义:
-
- typedef struct ip_header {
- u_char ver_ihl;
- u_char tos;
- u_short tlen;
- u_short identification;
- u_short flags_fo;
- u_char ttl;
- u_char proto;
- u_short crc;
- ip_address saddr;
- ip_address daddr;
- u_int op_pad;
- }ip_header;
我们可以通过首部长度得到UDP数据包的位置。下面的代码计算首部长度:
- ip_len = (ih->ver_ihl & 0xf) * 4;
得到首部长度后就可以得到UDP的位置了。下图是UDP报头的格式:
同样,UDP结构也需要我们自己定义:
-
- typedef struct udp_header {
- u_short sport;
- u_short dport;
- u_short len;
- u_short crc;
- }udp_header;
这里涉及到小端法和大端法。下面简单介绍一下。
《UNXI网络编程》定义:术语“小端”和“大端”表示多字节值的哪一端(小端或大端)存储在该值的起始地址。小端存在起始地址,即是小端字节序;大端存在起始地址,即是大端字节序。
也就是说,小端法(Little-Endian)将低位字节存储在内存的低地址即起始地址处,高字节存储在高地址;而大端法(Big-Endian)将低位字节存储在高地址,将高位字节存储在低地址处。
举个例子,对于整形0x12345678。它在大端法和小端法的系统内中,分别如下图所示的方式存放:
还有一个概念叫网络字节序,我们知道网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。
网络字节序说是大端字节序。
比如我们经过网络发送0x12345678这个整形,在80X86平台中,它是以小端法存放的,在发送前需要使用系统提供的htonl将其转换成大端法存放,如下图:
因此,对于多字节属性,需要使用函数在网络字节序和主机字节序中转换。
下面是程序的主要代码,将UDP的源IP地址、源端口、目的IP地址、目的端口打印出来:
- #include "pcap.h"
-
-
- typedef struct ip_address{
- u_char byte1;
- u_char byte2;
- u_char byte3;
- u_char byte4;
- }ip_address;
-
-
- typedef struct ip_header{
- u_char ver_ihl;
- u_char tos;
- u_short tlen;
- u_short identification;
- u_short flags_fo;
- u_char ttl;
- u_char proto;
- u_short crc;
- ip_address saddr;
- ip_address daddr;
- u_int op_pad;
- }ip_header;
-
-
- typedef struct udp_header{
- u_short sport;
- u_short dport;
- u_short len;
- u_short crc;
- }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[] = "ip and udp";
- struct bpf_program fcode;
-
-
- if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
- {
- fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
- exit(1);
- }
-
-
- for(d=alldevs; d; d=d->next)
- {
- printf("%d. %s", ++i, d->name);
- if (d->description)
- printf(" (%s)\n", d->description);
- else
- printf(" (No description available)\n");
- }
-
- if(i==0)
- {
- printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
- return -1;
- }
-
- printf("Enter the interface number (1-%d):",i);
- scanf("%d", &inum);
-
- if(inum < 1 || inum > i)
- {
- printf("\nInterface number out of range.\n");
-
- pcap_freealldevs(alldevs);
- return -1;
- }
-
-
- for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
-
-
- if ( (adhandle= pcap_open(d->name,
- 65536,
-
- PCAP_OPENFLAG_PROMISCUOUS,
- 1000,
- NULL,
- errbuf
- ) ) == NULL)
- {
- fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
-
- pcap_freealldevs(alldevs);
- return -1;
- }
-
-
- if(pcap_datalink(adhandle) != DLT_EN10MB)
- {
- fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
-
- pcap_freealldevs(alldevs);
- return -1;
- }
-
- if(d->addresses != NULL)
-
- netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
- else
-
- netmask=0xffffff;
-
-
-
- if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
- {
- fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
-
- pcap_freealldevs(alldevs);
- return -1;
- }
-
-
- if (pcap_setfilter(adhandle, &fcode)<0)
- {
- fprintf(stderr,"\nError setting the filter.\n");
-
- pcap_freealldevs(alldevs);
- return -1;
- }
-
- printf("\nlistening on %s...\n", d->description);
-
-
- pcap_freealldevs(alldevs);
-
-
- pcap_loop(adhandle, 0, packet_handler, NULL);
-
- return 0;
- }
-
-
- 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;
- time_t local_tv_sec;
-
-
- local_tv_sec = header->ts.tv_sec;
- ltime=localtime(&local_tv_sec);
- strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
-
-
- printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
-
-
- ih = (ip_header *) (pkt_data +
- 14);
-
-
- ip_len = (ih->ver_ihl & 0xf) * 4;
- uh = (udp_header *) ((u_char*)ih + ip_len);
-
-
- sport = ntohs( uh->sport );
- dport = ntohs( uh->dport );
-
-
- printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
- 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);
- }
运行结果如下:
原文地址:http://blog.csdn.net/u012877472/article/details/49846867