winpcap学习笔记--(Interpreting the packets)

尼玛,学了三年了,终于亲自接触到了IP包,好激动地说,哈哈哈哈哈哈

#define WIN32
#define HAVE_REMOTE

#include 
#include 
#include 

#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"wsock32.lib")


//Q:how many bits dose u_char hold  
/*
8个bit位
*/
//Q:bit,byte and word!!!!extremely important!!!!!!
/*
8位(bit)=1字节(Byte),1024字节=1KB;
字节是固定由8位二进制构成,64位系统就代表了64位的二进制代表一个字,换算成字节就是64/8=8,
即是说由8字节构成一个字,32位系统就是32/8=4,4个字节代表一个字。
字
    计算机进行数据处理时,一次存取、加工和传送的数据长度称为字(word)
在计算机中,一串数码作为一个整体来处理或运算的,称为一个计算机字,简称字。字通常分为若干个字节(每个字节一般是8位)。
在存储器中,通常每个单元存储一个字,因此每个字都是可以寻址的。字的长度用位数来表示。
在计算机的运算器、控制器中,通常都是以字为单位进行传送的。字出现在不同的地址其含义是不相同。
例如,送往控制器去的字是指令,而送往运算器去的字就是一个数。
*/
/*4 bytes IP address*/
typedef struct ip_address{
	u_char byte1;
	u_char byte2;
	u_char byte3;
	u_char byte4;
}ip_address;


//ip_header details
/*
http://blog.csdn.net/achejq/article/details/7040687
*/
/*IPv4 header*/
//注意ip header的结构不能乱!!!!必须遵守ip header的标准
typedef struct ip_header{
	u_char ver_ihl;			//Version (4 bits) + Internet header length (4 bits)
	u_char tos;				//Type of service
	u_short tlen;			//Total length
	u_short identification;	//Identification
	u_short flags_fo;		//Flags (3 bits) + Fragment offset (13 bits)
	u_char ttl;				// Time to live
	u_char proto;			// Protocol
	u_short crc;			// Header checksum
	ip_address saddr;
	ip_address daddr;
	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;

/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);


int 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 tcp";
	struct bpf_program fcode;//??

	/* Retrieve the device list */
	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
	{
		fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
		exit(1);
	}

	/* Print the list */
	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_s("%d", &inum);

	if(inum < 1 || inum > i)
	{
		printf("\nInterface number out of range.\n");
		/* 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(	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.
								PCAP_OPENFLAG_PROMISCUOUS,         // promiscuous mode
								1000,      // read timeout
								NULL,      // remote authentication
								errbuf     // error buffer
								) ) == NULL)
	{
		fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
		/* 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,"\nThis program works only on Ethernet networks.\n");
		/* 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*/
	//pcap_compile
	/*
	int pcap_compile	(	
		pcap_t * 	p,
		struct bpf_program * 	fp,
		char * 	str,
		int 	optimize,
		bpf_u_int32 	netmask	 
	)			
	Compile a packet filter, converting an high level filtering expression (see Filtering expression syntax) in a program that can be interpreted by the kernel-level filtering engine.

	pcap_compile() is used to compile the string str into a filter program. program is a pointer to a bpf_program struct and is filled in by pcap_compile(). optimize controls whether 
	optimization on the resulting code is performed. netmask specifies the IPv4 netmask of the network on which packets are being captured; it is used only when checking for IPv4 broadcast 
	addresses in the filter program. If the netmask of the network on which packets are being captured isn't known to the program, or if packets are being captured on the Linux "any" 
	pseudo-interface that can capture on more than one network, a value of 0 can be supplied; tests for IPv4 broadcast addreses won't be done correctly, but all other tests in the filter
	program will be OK. A return of -1 indicates an error in which case pcap_geterr() may be used to display the error text.
	*/
	if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0){
		fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
		/* Free the device list */
		pcap_freealldevs(alldevs);
		return -1;
	}

	/*set the filter*/
	//pcap_setfilter
	/*

	int pcap_setfilter	(	pcap_t * 	p,
	struct bpf_program * 	fp	 
	)			
	Associate a filter to a capture.
	pcap_setfilter() is used to specify a filter program. fp is a pointer to a bpf_program struct, usually the result of a call to pcap_compile(). -1 is returned on failure, in which case 
	pcap_geterr() may be used to display the error text; 0 is returned on success.
	*/
	if(pcap_setfilter(adhandle,&fcode)<0){
		fprintf(stderr,"\nError setting the filter.\n");
		/* Free the device list */
		pcap_freealldevs(alldevs);
		return -1;
	}
	printf("\nlistening on %s...\n", d->description);

	/* 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;
}
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;

	/*
	 *Unused variable
	 */
	(VOID)(param);

	/* convert the timestamp to readable format */
	local_tv_sec = header->ts.tv_sec;
	localtime_s(ts.tv_usec, header->len);

	
	//what is 0xf
	/*
	0x30 & 0xf = 00100111 & 00001111 = 0x00000111 = 0x07
	*/

	//why the len should multiply 4?
	/*
	IP包头长度(Header Length):长度4比特。这个字段的作用是为了描述IP包头的长度,因为在IP包头中有变长的可选部分。该部分占4个bit位,单位为32bit(4个字节),
	即本区域值= IP头部长度(单位为bit)/(8*4),因此,一个IP包头的长度最长为“1111”,即15*4=60个字节。IP包头最小长度为20字节。
	*/
	/*retrieve the position of the ip header*/
	ih=(ip_header *)(pkt_data + 14);		//length of ethernet header
	/*retrieve the position of the udp header*/
	ip_len=(ih->ver_ihl & 0xf)*4;			//count how many bytes in the ip_header
	uh=(udp_header *)((u_char *)ih+ip_len);	//ignore the ip_header and meet the udp_header.Controled by memory address.

	/*convert from network byte order to host byte order*/
	//ntohs()
	/*
	将一个无符号短整形数从网络字节顺序转换为主机字节顺序。
	#include 
	uint16_t ntohs(uint16_t netshort);
	*/
	sport=ntohs(uh->sport);
	dport=ntohs(uh->dport);

	/*print ip address and udp port*/
	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);

}

你可能感兴趣的:(WinpCap学习录)