实现一个简单的sniffer

#include<stdio.h>
#include<pcap.h>
#include<unistd.h>
#include<stdlib.h>
//#include<pcap/bpf.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<netinet/tcp.h>
#include<netinet/udp.h>
#include<netinet/ether.h>
#include<arpa/inet.h>
#define ETHER_SIZE 14

///get_packet()回调函数
///header:收到的数据包的pcap_pkthdr类型的指针
///packet:收到的数据包数据
void get_packet(u_char*args, const struct pcap_pkthdr *header,const u_char *packet){
	
	static int count = 1;
	const char * payload;
	printf("==================================packet number: %d=============================
",count++);
	
	///ETHER_SIZE:以太帧首部长度14个字节
	///IP包头(tcp包头(数据))
	///IP包头(udp包头(数据))
	///IP包头(icmp包头(数据))
	struct ip * ip = (struct ip *)(packet + ETHER_SIZE);
	printf("IP header length: %d
",ip->ip_hl<<2);
	printf("From %s
",inet_ntoa(ip->ip_src));
	printf("To %s
",inet_ntoa(ip->ip_dst));
	int ip_hl = ip->ip_hl<<2;

	///对报文类型进行了扩展
	///可以分析IP包、ICMP包、TCP包、UDP包
	switch(ip->ip_p){

		case IPPROTO_TCP:
		{
			printf("----Protocol TCP----
");
			struct tcphdr *tcp = (struct tcphdr *)(packet + 14 + ip_hl);			
			printf("tcp -> source:%d
",ntohs(tcp -> source));
			printf("tcp -> dest:%d
",ntohs(tcp -> dest));
			printf("tcp -> seq:%d
",ntohs(tcp -> seq));
			printf("tcp -> ack_seq:%d
",ntohs(tcp -> ack_seq));		
			printf("tcp -> headerLenth:%d
",tcp -> doff << 2);
			printf("tcp -> fin:%d
",tcp -> fin);
			printf("tcp -> syn:%d
",tcp -> syn);
			printf("tcp -> rst:%d
",tcp -> rst);
			printf("tcp -> psh:%d
",tcp -> psh);
			printf("tcp -> ack:%d
",tcp -> ack);
			printf("tcp -> urg:%d
",tcp -> urg);
			printf("tcp -> window:%d
",ntohs(tcp -> window));
			printf("tcp -> check:%d
",ntohs(tcp -> check));	
			//printf("tcp -> urg_ptr:%d
",tcp -> urg_ptr);
			
			int h_size = tcp->doff<< 2;
			int payload_size = ntohs(ip->ip_len) - ip_hl - h_size;
			
			int i = payload_size;
			printf("payload is:%d
",i);
			
			while(i > 0)
			{
				printf("%02x  ", packet[i]);
				if( i % 16 == 0 )
					printf("
");
				i--;
			}
			printf("
");
			break;
		}
		case IPPROTO_UDP:
		{
			printf("----Protocol UDP----
");
			struct udphdr *udp = (struct udphdr *)(packet + 14 + ip_hl);			
			printf("udp -> source:%d
",ntohs(udp -> source));
			printf("udp -> dest:%d
",ntohs(udp -> dest));
			printf("udp -> length:%d
",ntohs(udp -> len));
			printf("udp -> check:%d
",ntohs(udp -> check));
			int payload_size = ntohs(ip->ip_len) - ip_hl - 8;
			int i = payload_size;
			printf("payload is:%d
",i);
			
			while(i > 0)
			{
				printf("%02x  ", packet[i]);
				if( i % 16 == 0 )
					printf("
");
				i--;
			}
			printf("
");
			break;
		}
		case IPPROTO_ICMP:
		{
			printf("----Protocol ICMP----
");
			struct icmphdr *icmp = (struct icmphdr *)(packet + 14 + ip_hl);

			if(icmp -> type == 8)
			{
				printf("--icmp_echo request--
");
				printf("icmp -> type:%d
",icmp -> type);
				printf("icmp -> code:%d
",icmp -> code);
				printf("icmp -> checksum:%d
",icmp -> checksum);
	
				printf("icmp -> id:%d
",icmp -> un.echo.id);
				printf("icmp -> sequence:%d
",icmp -> un.echo.sequence);
				int payload_size = ntohs(ip->ip_len) - ip_hl - 8;
				int i = payload_size;
				printf("payload is:%d
",i);
			
				while(i > 0)
				{
					printf("%02x  ", packet[i]);
					if( i % 16 == 0 )
						printf("
");
					i--;
				}
				printf("
");
			}
			else if(icmp -> type == 0)
			{
				printf("--icmp_echo reply--
");
				printf("icmp -> type:%d
",icmp -> type);
				printf("icmp -> code:%d
",icmp -> code);
				printf("icmp -> checksum:%d
",icmp -> checksum);				

				printf("icmp -> id:%d
",icmp -> un.echo.id);
				printf("icmp -> sequence:%d
",icmp -> un.echo.sequence);
				int payload_size = ntohs(ip->ip_len) - ip_hl - 8;
				int i = payload_size;
				printf("payload is:%d
",i);
			
				while(i > 0)
				{
					printf("%02x  ", packet[i]);
					if( i % 16 == 0 )
						printf("
");
					i--;
				}
				printf("
");
			}
			else
			{
				printf("icmp -> type:%d
",icmp -> type);
				printf("icmp -> code:%d
",icmp -> code);
				printf("icmp -> checksum:%d
",icmp -> checksum);
				int payload_size = ntohs(ip->ip_len) - ip_hl - 8;
				int i = payload_size;
				printf("payload is:%d
",i);
			
				while(i > 0)
				{
					printf("%02x  ", packet[i]);
					if( i % 16 == 0 )
						printf("
");
					i--;
				}
				printf("
");		
			}
			break;		
		}
		case IPPROTO_IP:
		{
			printf("----Protocol IP----
");
			//printf("IP header length: %d
",ip -> ip_hl<<2);
			printf("IP version: %d
",ip -> ip_v);
			printf("IP type of service: %d
",ip -> ip_tos);
			printf("IP total length: %d
",ip -> ip_len);
			printf("IP identification: %d
",ip -> ip_id);
			printf("IP fragment offset field: %d
",ip -> ip_off);
			printf("IP time to live: %d
",ip -> ip_ttl);
			printf("IP protocol: %d
",ip -> ip_p);
			printf("IP checksum: %d
",ip -> ip_sum);
			int payload_size = ntohs(ip->ip_len) - ip_hl;
			int i = payload_size;
			printf("payload is:%d
",i);			
			while(i > 0)
			{
				printf("%02x  ", packet[i]);
				if( i % 16 == 0 )
					printf("
");
				i--;
			}
			printf("
");
			break;			
		}			
		default:printf("Protocol unknown
");
		return;
	

	}
}
		


int main(int argc,char*argv[]){

	char *dev, errbuf[PCAP_ERRBUF_SIZE];
	struct bpf_program fp;
	char filter_exp[] = "port 23";
	bpf_u_int32 mask;
	bpf_u_int32 net;
	struct pcap_pkthdr header;
	const u_char *packet;	
	int num_packets = 10;
	
	///pcap_lookupdev()自动获取网络接口,返回一个网络接口的字符串指针
	///如果出错,errbuf存放出错信息
	///若想手动指定,则跳过此步,将要监听的网络字符串硬编码到pcap_open_live中
	dev = pcap_lookupdev(errbuf);
	if(dev==NULL){
		printf("ERROR:%s
",errbuf);
		exit(2);
	}
	printf("The sniff interface is:%s
",dev);

	///pcap_lookupnet()获得设备的IP地址,子网掩码等信息
	///net:网络接口的IP地址
	///mask:网络接口的子网掩码
	if(pcap_lookupnet(dev,&net,&mask,errbuf)==-1){
		printf("ERROR:%s
",errbuf);
		net = 0;
		mask = 0;
	}	

	///pcap_open_live()打开网络接口
	///BUFSIZ:抓包长度
	///第三个参数:0代表非混杂模式,1代表混杂模式
	///第四个参数:等待的毫秒数,超过这个值,获取数据包的函数会立即返回,0表示一直等待直到有数据包到来
	pcap_t * handle = pcap_open_live(dev,BUFSIZ,1,0,errbuf);
	if(handle == NULL){
		printf("ERROR:%s
",errbuf);
		exit(2);
	}
/*这里我们测试发现不能过滤,注释掉这部分代码,程序可以正常运行了。
	///pcap_compile()编译过滤表达式
	///fp指向编译后的filter_exp
	///filter_exp过滤表达式
	///参数四:是否需要优化过滤表达式
	if(pcap_compile(handle,&fp,filter_exp,0,net)==-1){
		printf("Can't parse filter %s:%s
",filter_exp,pcap_geterr(handle));
		return(2);
	}
	
	///pcap_setfilter()应用这个过滤表达式
	///完成过滤表达式后,我们可以使用pcap_loop()或pcap_next()登抓包函数抓包了
	if(pcap_setfilter(handle,&fp)==-1){	
		printf("cant' install filter %s:%s
",filter_exp,pcap_geterr(handle));
		return(2);
	}	
*/
	printf("Hello
");	

//	packet = pcap_next(handle,&header);
//	printf("Get a packet with length %d.
",header.len);

	///
	///num_packets:需要抓的数据包的个数,一旦抓到了num_packets个数据包,pcap_loop立即返回。负数表示永远循环抓包,直到出错
	///get_packet:回调函数指针
	//pcap_loop(handle,num_packets,get_packet,NULL);
	pcap_loop(handle,-1,get_packet,NULL);
	
	pcap_freecode(&fp);
	
	///pcap_close()释放网络接口
	///关闭pcap_open_live()获取的pcap_t的网络接口对象并释放相关资源
	pcap_close(handle);
	return(0);
}

  

原文地址:https://www.cnblogs.com/ailx10/p/5459890.html