• 截获所有以太网帧数据并进行具体分析


    /* capture_packet.c - 截获所有以太网帧数据并进行具体分析 */
    
    /* 常用函数的头文件   */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>  
    #include <strings.h>
    #include <unistd.h>  
    #include <signal.h>
    
    /* 与网络相关的头文件 */
    #include <netinet/ip_icmp.h> 
    #include <net/if_arp.h>
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>   
    #include <netinet/ip.h>  
    #include <netdb.h>  
    #include <netinet/tcp.h>  
    #include <netinet/udp.h> 
    #include <signal.h>  
    #include <net/if.h>  
    #include <sys/ioctl.h>  
    #include <sys/stat.h>  
    #include <fcntl.h>  
    #include <linux/if_ether.h> 
    #include <net/ethernet.h>
    #include <linux/igmp.h>
    #include <netinet/tcp.h>
    
    
    /* 全局变量结构的结构体原型 - 包含要记录的任何全局信息 */
    struct global_info {
    	unsigned int bytes;		/* 网卡接收的总字节数     */
    	unsigned int packet_num;        /* 网卡接受的帧的总数量   */
    	
    	unsigned int packet_arp;        /* 接收到的arp包的数量    */
    	unsigned int packet_rarp;       /* 接收到的rarp包的数量   */
    
    	unsigned int packet_ip;		/* 接收到的ip包的数量     */
    	unsigned int packet_icmp;	/* 接收到的icmp包的数量   */
    	unsigned int packet_igmp;	/* 接收到的igmp包的数量   */
    
    	unsigned int packet_tcp;	/* 接收到的tcp包的数量    */
    	unsigned int packet_udp;	/* 接收到的udp包的数量    */
    	
    	int print_flag_frame;		/* 是否打印帧头信息标志, 1表示打印, 0表示不打印 */
    	int print_flag_arp;		/* 是否打印arp头信息标志  */
    	int print_flag_ip;		/* 是否打印ip头信息标志   */
    	int print_flag_rarp;		/* 是否打印rarp头信息标志 */
    	int print_flag_tcp;		/* 是否打印tcp头信息标志  */
    	int print_flag_udp;		/* 是否打印udp头信息标志  */
    	int print_flag_icmp;		/* 是否打印icmp头信息标志 */
    	int print_flag_igmp;		/* 是否打印igmp头信息标志 */
    };
    
    
    /* 定义一个全局变量,用于存储全局信息 */
    struct global_info global;
    
    struct ip_pair {
    	unsigned int source_ip;
    	unsigned int dest_ip;
    	unsigned int count;
    };
    
    /* 定义一个用于存储ip对的结构体数组 */
    struct ip_pair ip_pair[10000];
    
    /* 一个用于初始化全局信息的函数 */
    void init_global( struct global_info  * var );
    
    /* 一个用于打印全局信息的函数   */
    void print_global( struct global_info var );
    
    /* 打印一个错误,并退出 		*/
    void error_and_exit( char * msg, int exit_code );
    
    /* 设置网卡成混杂模式	        */
    int set_card_promisc( char * interface_name, int sock );
    
    /* 把mac地址转换一个字符串      */
    void mac_to_str( char * buf, char * mac_buf );
    
    /* 用于打印帮助信息 		*/
    void help( void );
    
    /* 截获网卡帧数据,并进行数据分用*/
    void do_frame( int sockfd );  
    
    
    /* 处理ip层数据		        */
    void do_ip( char * data );
    
    /* 打印ip头信息 	        */
    void print_ip( struct iphdr * );
    
    /* 处理arp层数据	       */
    void do_arp( char * data );
    
    /* 打印arp头信息 	       */
    void print_arp( struct arphdr * ); 
    
    /* 处理rarp数据		       */
    void do_rarp( char * data );
    
    
    /* 处理tcp层数据 	       */
    void do_tcp( char * data );
    
    /* 打印tcp层头信息 	       */
    void print_tcp( struct tcphdr * );
    
    /* 处理udp层数据 	       */
    void do_udp( char * data );
    
    /* 打印udp层头信息 	       */
    void print_udp( struct udphdr * );
    
    
    /* 处理icmp层数据	       */
    void do_icmp( char * data );
    
    /* 打印icmp头信息	       */
    void print_icmp( struct icmphdr * );
    
    /* 处理igmp层数据 	       */
    void do_igmp( char * data );
    
    /* 打印igmp头信息	       */
    void print_igmp( struct igmphdr * );
    
    
    
    /* 初始化一个全局结构体 	      */
    void init_global( struct global_info  * var )
    {
    	var->bytes = 0;
    	var->packet_num = 0;
    	
    	var->packet_arp = 0;
    	var->packet_rarp = 0;
    	var->packet_ip = 0;
    	var->packet_icmp = 0;
    	var->packet_igmp = 0;
    	var->packet_tcp = 0;
    	var->packet_udp = 0;
    	
    	var->print_flag_frame = 0;
    	var->print_flag_arp = 0;
    	var->print_flag_ip = 0;
    	var->print_flag_rarp = 0;
    	var->print_flag_tcp = 0;
    	var->print_flag_udp = 0;
    	var->print_flag_icmp = 0;
    	var->print_flag_igmp = 0;
    }
    
    /* 一个用于打印全局信息的函数  */
    void print_global( struct global_info var )
    {
    	printf("\n\n********** 全局信息 *****************\n\n");
    	printf("总共接收字节数: %d kbytes.\n", var.bytes / 1024 );
    	printf("总共接受包数量: %d\n\n", var.packet_num );
    	
    	if( var.packet_arp ) printf("接收 arp 包数量: %d\n", var.packet_arp );
    	if( var.packet_rarp) printf("接收 rarp 包数量: %d\n", var.packet_rarp );
    	if( var.packet_ip )  printf("接收 ip 包数量: %d\n", var.packet_ip );
    	if( var.packet_icmp) printf("接收 icmp 包数量: %d\n", var.packet_icmp );
    	if( var.packet_igmp) printf("接收 igmp 包数量: %d\n", var.packet_igmp );
    	if( var.packet_tcp ) printf("接收 tcp 包数量: %d\n", var.packet_tcp );
    	if( var.packet_udp ) printf("接收 udp 包数量: %d\n", var.packet_udp );
    	
    	printf("\n");
    }
    
    /* 用于处理当下按ctrl-c时的处理函数 */
    void sig_int( int sig )
    {
    	print_global( global );
    	
    	int i;
    	
    	/*
    	for( i=0; i<global.packet_ip; i++ ){
    		printf("%15s ==>> ", inet_ntoa( *(struct in_addr *)( &ip_pair[i].source_ip ) ) );
    		printf("%15s \n", inet_ntoa( *(struct in_addr *)( &ip_pair[i].dest_ip ) ));
    	}
    	*/
    
    	exit( 0 );
    }
    
    /* 打印错误信息,并退出            */
    void error_and_exit( char * msg, int exit_code )  
    {  
    	herror( msg );  
    	exit( exit_code );  
    }  
    
    /* 设置网卡模式成混帐模式,这样的话可以截获以太网帧数据 */
    int set_card_promisc( char * interface_name, int sock )  
    {  
    	/* 用于套接口ioctl的接口请求结构体 	*/
    	struct ifreq ifr; 
                    
    	/* 复制网卡名称进入请求结构体的名称元素 */
    	strncpy(ifr.ifr_name, interface_name ,strlen( interface_name )+1);  
    
    	/* 通过ioctl获得相应信息	        */
    	if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {       	
    	    error_and_exit("ioctl", 2);  
    	}  
    
    	/* 设置网卡模式标志为混杂模式	       */
        	ifr.ifr_flags |= IFF_PROMISC;  		            
    
    	/* 通过ioctl把参数传递给网卡	       */  
    	if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 )  	      
       	    error_and_exit("ioctl", 3);  
    }  
    
    /* 把mac地址转换成字符串 */
    void mac_to_str( char * buf, char * mac_buf )
    {
    	sprintf( mac_buf, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char) *buf, (unsigned char)(*(buf+1)), 
    					(unsigned char)(*(buf+2)), (unsigned char)(*(buf+3)),
    					(unsigned char)(*(buf+4)), (unsigned char)(*(buf+5)));
    	mac_buf[17] = 0;
    }
    
    void help( void )
    {
    	printf("Usage: capture [-h] [协议名称 ...].\n");
    	printf("默认情况: 打印所有包信息.\n");
    }
    
    void print_udp( struct udphdr * pudp )
    {
    	printf("==================== udp 头信息 ======================\n");
    	printf("16位源端口号  : %d\n", ntohs( pudp->source ) );
    	printf("16位目的端口号:	%d\n", ntohs( pudp->dest ) );
    	printf("16位udp长度: %d\n", ntohs( pudp->len ) );
    	printf("16位udp校验和: %d\n", ntohs( pudp->check ) );
    	if( ntohs( pudp->len ) != sizeof(struct udphdr ) && ntohs( pudp->len ) < 20 ){
    		char * data = ( char * )pudp + sizeof( struct udphdr );
    		printf("UDP数据: %s\n", data );
    	}
    }
    
    void do_udp( char * data )
    {
    	global.packet_udp ++;
    
    	struct udphdr * pudp = ( struct udphdr * )data;
    	if( global.print_flag_udp )
    		print_udp( pudp );	
    }
    
    
    void print_tcp( struct tcphdr * ptcp )
    {
    	printf("==================== tcp 头信息 =====================\n");
    	printf("源端口号  : %d\n", ntohs( ptcp->source ) );
    	printf("目的端口号: %d\n", ntohs( ptcp->dest ) );
    	printf("32位序列号  : %u\n", ntohl( ptcp->seq ) );
    	printf("32位确认序号: %u\n", ntohl( ptcp->ack_seq ) );
    	printf("首部长度: %d\n", ptcp->doff * 4 );
    	printf("6个标志位: \n");
    	printf("    紧急指针 urg : %d\n", ptcp->urg );
    	printf("    确认序号位 ack : %d\n", ptcp->ack );
    	printf("    接受方尽快将报文交给应用层 psh : %d\n", ptcp->psh );
    	printf("    重建连接 rst : %d\n", ptcp->rst );
    	printf("    用来发起连接的同步序号 syn : %d\n", ptcp->syn );
    	printf("    发送端完成任务 fin : %d\n", ptcp->fin );
    	printf("16位窗口大小: %d\n", ntohs( ptcp->window ) );
    	printf("16位校验和: %d\n", ntohs( ptcp->check ) );
    	printf("16位紧急指针: %d\n", ntohs( ptcp->urg_ptr ) );
    		
    	if( ptcp->doff * 4 == 20 ){
    		printf("选项数据: 没有\n");
    	} else {
    		printf("选项数据: %d 字节\n", ptcp->doff * 4 - 20 );
    	}
    	
    	char * data = ( char * )ptcp;
    	data += ptcp->doff * 4;
    	printf("数据长度: %d 字节\n", strlen(data) );
    	if( strlen(data) < 10 )printf("数据: %s\n", data );
    }
    
    void do_tcp( char * data )
    {
    	global.packet_tcp ++;
    
    	struct tcphdr * ptcp;
    	ptcp = ( struct tcphdr * )data;
    	
    	if( global.print_flag_tcp )	
    		print_tcp( ptcp );
    }
    
    void print_igmp( struct igmphdr * pigmp )
    {
    	printf("====================  igmp 包信息 ==========================\n");
    	printf("igmp 版本: %d\n", pigmp->type & 15 );
    	printf("igmp 类型: %d\n", pigmp->type >> 4 );
    	printf("igmp 码: %d\n", pigmp->code );
    	printf("igmp 校验和: %d\n", ntohs( pigmp->csum ) );
    	printf("igmp 组地址: %d\n", ntohl( pigmp->group ) );
    }
    
    void do_igmp( char * data )
    {
    	global.packet_igmp ++;
    	struct igmphdr * pigmp = ( struct igmphdr * ) data;
    	
    	if( global.print_flag_igmp )
    		print_igmp( pigmp );
    }
    
    void print_icmp( struct icmphdr * picmp )
    {
    	printf("==================== icmp 包信息 ===========================\n");
    	
    	printf("消息类型: %d ", picmp->type );
    		switch( picmp->type ){
    			case ICMP_ECHOREPLY:
    				printf("Ping的回显应答\n");
    				break;
    			case ICMP_DEST_UNREACH:
    			      	printf("目的不可达\n"); 
    				break;
    			case ICMP_SOURCE_QUENCH:
    				printf("源端被关闭\n");
    				break;
    			case ICMP_REDIRECT:
    				printf("重定相\n");  
    				break;
    			case ICMP_ECHO:
    				printf("ping的回显请求\n");    
    				break;
    			case ICMP_TIME_EXCEEDED:
    				printf("超时\n");
    				break;
    			case ICMP_PARAMETERPROB:
    				printf("参数问题\n"); 
    				break;
    			case ICMP_TIMESTAMP:
    				printf("时间戳请求\n");   
    				break;
    			case ICMP_TIMESTAMPREPLY:
    				printf("时间戳应答\n");   
    				break;
    			case ICMP_INFO_REQUEST:
    				printf("信息请求\n");  
    				break;
    			case ICMP_INFO_REPLY:
    				printf("信息应答\n"); 
    				break;
    			case ICMP_ADDRESS:
    				printf("地址掩码请求\n"); 
    				break;
    			case ICMP_ADDRESSREPLY:
    				printf("地址掩码应答\n"); 
    				break;
    			default:
    				printf("未知消息类型\n");
    				break;
    		}
    	printf("消息类型的子选项: %d ", picmp->code );
    		switch( picmp->type ){
    			case ICMP_ECHOREPLY:
    				printf("Ping的回显应答\n");
    				break;
    			case ICMP_DEST_UNREACH:
    				switch( picmp->type ){
    					case ICMP_NET_UNREACH:
    						printf("网络不可到达\n"); 
    						break;
    					case ICMP_HOST_UNREACH:
    						printf("主机不可到达\n");  
    						break;
    					case  ICMP_PROT_UNREACH:
    						printf("协议不可到达\n");
    						break;  
    					case  ICMP_PORT_UNREACH:
    						printf("端口不可到达\n");
    						break;
    					case  ICMP_FRAG_NEEDED:
    						printf("需要进行分片,但是又设置不分片位\n"); 
    						break;
    					case  ICMP_SR_FAILED:
    						printf("源站选路失败\n"); 
    						break;
    					case  ICMP_NET_UNKNOWN:
    						printf("目的网络不认识\n");
    						break;
    					case  ICMP_HOST_UNKNOWN:
    						printf("目的主机不认识\n");
    						break;
    					case  ICMP_HOST_ISOLATED:
    						printf("源主机北隔离\n");
    						break;
    					case  ICMP_NET_ANO:
    						printf("目的网络被强制禁止\n");
    						break;
    					case  ICMP_HOST_ANO:
    						printf("目的主机被强制禁止\n");
    						break;
    					case  ICMP_NET_UNR_TOS:
    						printf("由于服务类型TOS,网络不可到达\n");
    						break;
    					case  ICMP_HOST_UNR_TOS:
    						printf("由于服务类型TOS,主机不可到达\n");
    						break;
    					case  ICMP_PKT_FILTERED:
    						printf("由于过滤,通信被强制禁止\n");
    						break;
    					case  ICMP_PREC_VIOLATION:
    						printf("主机越权\n");
    						break;
    					case  ICMP_PREC_CUTOFF:
    						printf("优先权中止生效\n");
    						break;
    					default:
    						printf("未知代码\n");
    						break;
    
    				}
    				break;
    			case ICMP_SOURCE_QUENCH:
    				printf("源端被关闭\n");
    				break;
    			case ICMP_REDIRECT:
    				switch( picmp->type ){
    					case ICMP_REDIR_NET:
    						printf("对网络重定向\n");
    						break;
    					case ICMP_REDIR_HOST:
    						printf("对主机重定向\n");   
    						break;
    					case ICMP_REDIR_NETTOS:
    						printf("对服务类型和网络重定向\n");  
    						break;
    					case ICMP_REDIR_HOSTTOS:
    						printf("对服务类型和主机重定向\n"); 
    						break;
    					defalut:
    						printf("未知代码\n");
    						break;
    				}
    				break;
    			case ICMP_ECHO:
    				printf("ping的回显请求\n");    
    				break;
    			case ICMP_TIME_EXCEEDED:
    				switch( picmp->type ){
    					case ICMP_EXC_TTL:
    						printf("在传输期间生存时间为0\n");
    						break;
    					case ICMP_EXC_FRAGTIME:
    						printf("在数据组装期间生存时间为0\n"); 
    						break;
    					default:
    						printf("未知代码\n");
    						break;
    				}
    				break;
    			case ICMP_PARAMETERPROB:
    				switch( picmp->type ){
    					case 0:
    						printf("IP首部错误(包括各种差错)\n");
    						break;
    					case 1:
    						printf("缺少必须的选项\n");
    						break;
    					default:
    						printf("原因未知\n"); 
    						break;
    				}
    				break;
    			case ICMP_TIMESTAMP:
    				printf("时间戳请求\n");   
    				break;
    			case ICMP_TIMESTAMPREPLY:
    				printf("时间戳应答\n");   
    				break;
    			case ICMP_INFO_REQUEST:
    				printf("信息请求\n");  
    				break;
    			case ICMP_INFO_REPLY:
    				printf("信息应答\n"); 
    				break;
    			case ICMP_ADDRESS:
    				printf("地址掩码请求\n"); 
    				break;
    			case ICMP_ADDRESSREPLY:
    				printf("地址掩码应答\n"); 
    				break;
    			default:
    				printf("未知消息类型\n");
    				break;
    		}
    
    	printf("校验和: %d\n", ntohs(picmp->checksum) );
    }
    
    void do_icmp( char * data )
    {
    	global.packet_icmp ++;
    
    	struct icmphdr * picmp = ( struct icmphdr * ) data;
    	
    	if( global.print_flag_icmp )
    		print_icmp( picmp );
    }
    
    void print_ip( struct iphdr * iph )
    {
    	printf("=============== ip 头信息 ===============\n");
    	printf("IP 首部长度:%d\n", iph->ihl * 4 );
    	printf("IP 版本    :%d\n", iph->version );
    	printf("服务类型(tos): %d\n", iph->tos );
    	printf("总长度字节: %d\n", ntohs(iph->tot_len) );
    	printf("16位标识: %d\n", ntohs(iph->id) );
    	printf("frag off: %d\n", ntohs(iph->frag_off) );
    	printf("8位生存事件: %d\n", iph->ttl );
    	printf("8位协议: %d\n", iph->protocol );
    	printf("16位首部校验和: %d\n", ntohs(iph->check) );
    	printf("32位源IP地址  : %s\n", inet_ntoa( *(struct in_addr *)(&iph->saddr)) );
    	printf("32位目的IP地址: %s\n", inet_ntoa( *(struct in_addr *)(&iph->daddr)) );
    		
    }
    
    void ip_count( struct iphdr * iph )
    {
    	ip_pair[ global.packet_ip - 1 ].source_ip = iph->saddr;
    	ip_pair[ global.packet_ip - 1 ].dest_ip = iph->daddr;
    }
    
    void do_ip( char * data )
    {
    	global.packet_ip ++;
    
    	struct iphdr *pip;         
    	pip = ( struct iphdr * ) data;    /* pip = point to ip layer */
    	if( global.print_flag_ip )
    		print_ip( pip );
    	
    	ip_count( pip );
    	
    	char * pdata = data + pip->ihl * 4;
    	
    	switch( pip->protocol ){
    		case IPPROTO_ICMP:
    			do_icmp( pdata );
    			break;
    		case IPPROTO_IGMP:
    			do_igmp( pdata );
    			break;
    		case IPPROTO_TCP:
    			do_tcp( pdata );
    			break;
    		case IPPROTO_UDP:
    			do_udp( pdata );
    			break;
    		default:
    			printf("IP: 未知其上层协议.\n");
    			break;
    	}
    }
    
    void print_arp( struct arphdr * parp )
    {
    
    	printf("硬件类型: %d ", ntohs(parp->ar_hrd) );
    		switch( ntohs( parp->ar_hrd ) ){
    			case ARPHRD_ETHER:
    				printf("Ethernet 10/100Mbps.\n");	
    				break;
    			case ARPHRD_EETHER:
    				printf("Experimental Ethernet.\n");
    				break;
    			case ARPHRD_AX25:
    				printf("AX.25 Level 2.\n");
    				break;
    			case ARPHRD_PRONET:
    				printf("PROnet token ring.\n");
    				break;
    			case ARPHRD_IEEE802:
    				printf("IEEE 802.2 Ethernet/TR/TB.\n");
    				break;
    			case ARPHRD_APPLETLK:
    				printf("APPLEtalk.\n");
    				break;
    			case ARPHRD_ATM:	
    				printf("ATM.\n");						
    				break;
    			case ARPHRD_IEEE1394:
    				printf("IEEE 1394 IPv4 .\n");
    				break;
    			default:
    				printf("Unknow.\n");
    				break;
    		}
    	printf("映射的协议地址类型: %d ", ntohs(parp->ar_pro) );
    		switch( ntohs(parp->ar_pro) ){
    			case ETHERTYPE_IP:
    				printf("IP.\n");
    				break;
    			default:
    				printf("error.\n");
    				break;
    		}
    	printf("硬件地址长度: %d\n", parp->ar_hln );
    	printf("协议地址长度: %d\n", parp->ar_pln );
    	printf("操作码: %d ", ntohs(parp->ar_op) );
    		switch( ntohs(parp->ar_op) ){
    			case ARPOP_REQUEST:
    				printf("ARP 请求.\n");
    				break;
    			case ARPOP_REPLY:	
    				printf("ARP 应答.\n");
    				break;
    			case ARPOP_RREQUEST:
    				printf("RARP 请求.\n");
    				break;
    			case ARPOP_RREPLY:
    				printf("RARP 应答.\n");
    				break;
    			case ARPOP_InREQUEST:
    				printf("InARP 请求.\n");
    				break;
    			case ARPOP_InREPLY:
    				printf("InARP 应答.\n");			
    				break;
    			case ARPOP_NAK:
    				printf("(ATM)ARP NAK.\n");
    				break;
    			default:
    				printf("arp 操作码错误.\n");
    				break;
    		}
    	
    	char * addr = (char*)(parp + 1);
    	char buf[18];
    	mac_to_str( addr, buf ); 
    	printf("发送端以太网地址: %s\n", buf );
    	printf("发送端IP地址:     %s\n", inet_ntoa( *(struct in_addr *)(addr+6) ));
    	mac_to_str( addr+10, buf );
    	printf("目的以太网地址: %s\n", buf );
    	printf("目的IP地址:     %s\n", inet_ntoa( *(struct in_addr *)(addr+16) ));
    }
    
    void do_arp( char * data )
    {
    	global.packet_arp ++;
    
    	struct arphdr * parp;
    	parp = ( struct arphdr * ) data;
    	
    	if( global.print_flag_arp ) {
    		printf("============= arp 头信息 ==============\n");
    		print_arp( parp );
    	}
    }
    
    void do_rarp( char * data )
    {
    	global.packet_rarp ++;
    
    
    	struct arphdr * parp;
    	parp = ( struct arphdr * ) data;
    	
    	if( global.print_flag_rarp ){
    		printf("============= rarp 头信息 =============\n");
    		print_arp( parp );
    	}
    }
    
    /* 打印以太网帧的包头信息 */
    void print_frame( struct ether_header * peth )
    {
    	/* 定义一个数组,用于存储把mac地址转换成字符串后的字符串 */
    	char buf[ 18 ];
    
    	printf("\n==================================   第 %d 个包  =======================================\n\n", global.packet_num );
    	printf("==== 以太网帧信息 =====\n");
    	char * shost = peth->ether_shost;
    	mac_to_str( shost, buf );		
    	printf("源以太网地址:  %s\n", buf );
    	
    	char * dhost = peth->ether_dhost;
    	mac_to_str( dhost, buf );
    	printf("目的以太网地址:%s\n", buf );
    }
    
    
    /* 用于从网卡接受一帧数据,同时根据以太网协议字段传递数据给相应的上层协议处理 */
    void do_frame( int sock )
    {
    	/* 用于存储一帧数据         */
    	char frame_buf[ 2000 ];
    	
    	/* 清空帧数据缓冲区	    */
    	bzero( frame_buf, sizeof(frame_buf) );
    
    	int len = sizeof( frame_buf );
    	
    	/* 用于存储接受字节数       */
    	int recv_num;
    
    	/* 用于存储发送方的地址信息 */
    	struct sockaddr_in addr;
    
    	/* 从网卡接收一帧数据       */
            recv_num = recvfrom( sock, (char *)frame_buf, sizeof( frame_buf ), 0, ( struct sockaddr * )&addr, &len );  
    
    	/* 所接收的包的总数自加1    */
    	global.packet_num ++;
    
    	/* 从网卡接收的字节总数     */
    	global.bytes += recv_num;
    
    	/* 打印接收的包是第几个包   */
    	//printf("此帧数据长度: %d\n", recv_num );
    	
    	/* 定义一个用于指向以太网帧的指针 (这里我们只考虑最常见的以太网帧的情况) */
    	struct ether_header * peth; 
    
    	/* 让以太网头指针指向从网卡接受到的帧的数据的开头 */
            peth = (struct ether_header *)frame_buf; 
    
    	/* 传递以太网帧首地址给打印以太网帧信息的打印函数 */
    	if( global.print_flag_frame )
    		print_frame( peth );
    
    	/* 定义一个数据指针,用于指向以太网帧的数据部分    */
    	char * pdata;
    
    	/* 让 pdata 指向以太网帧的数据部分                */
    	pdata = frame_buf + sizeof( struct ether_header );
    
    	/* 根据以太网帧的协议字段进行数据分用 - 也就是进行数据拆封,根据协议字段调用相应层的处理函数 */
            switch( ntohs( peth->ether_type ) ){
         		case ETHERTYPE_PUP:
    			break;
    		case ETHERTYPE_IP:
    			do_ip( pdata );
    			break;
    		case ETHERTYPE_ARP:
    			do_arp( pdata );
    			break;
    		case ETHERTYPE_REVARP:
    			do_rarp( pdata );
    			break;
    		default:
    			printf("Unkonw ethernet type  %d %x.\n", ntohs(peth->ether_type), ntohs(peth->ether_type) );
    			break;
           }
    }
    
    
    /* 主函数, 处理命令行输入, 设置好全局变量, 并调用接受和处理帧的函数 */
    
    int main( int argc, char ** argv )  
    {  
    	/* 用于存储套接口文件描述符 */
    	int sockfd;
    
    	/* 初始化全局变量 	  */
    	init_global( &global );
    
    	if( argc == 1 ) {       		/* 表示打印所有包头信息 */
    		global.print_flag_frame = 1;
    		global.print_flag_arp = 1;
    		global.print_flag_ip = 1;
    		global.print_flag_rarp = 1;
    		global.print_flag_tcp = 1;
    		global.print_flag_udp = 1;
    		global.print_flag_icmp = 1;
    		global.print_flag_igmp = 1;
    	} else {		       /* 帮助 或者 通过指定协议名称只打印某层些协议 */
    		if( !strcasecmp( argv[1], "-h" ) ){
    			help();
    			exit( 0 );
    		} else { 
    			int i;
    			for( i=1; i < argc; i++ ){
    				if( !strcasecmp( argv[i], "frame" ) )
    					global.print_flag_frame = 1;
    				else if( !strcasecmp( argv[i], "arp" ) )
    					global.print_flag_arp = 1;
    				else if( !strcasecmp( argv[i], "rarp" ) )
    					global.print_flag_rarp = 1;
    				else if( !strcasecmp( argv[i], "ip" ) )
    					global.print_flag_ip = 1;
    				else if( !strcasecmp( argv[i], "tcp" ) )
    					global.print_flag_tcp = 1;
    				else if( !strcasecmp( argv[i], "udp" ) )
    					global.print_flag_udp = 1;
    				else if( !strcasecmp( argv[i], "icmp" ) )
    					global.print_flag_icmp = 1;
    				else if( !strcasecmp( argv[i], "igmp" ) )
    					global.print_flag_igmp = 1;
    			}
    		}
    	}
    	
    	/* 通过协议族AF_PACKET类信SOCK_RAW, 类型SOCK_RAW创建一个用于可以接受网卡帧数据的套接口,同时返回套就口文件描述符 */
    	if( (sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) ) == -1 ) 
    	        error_and_exit( "socket", 1 );  /* 如果发生错误,返回错误值, 并退出 */
    
    	
    	/* 设定网卡eth0成混杂模式 */
    	set_card_promisc( "eth0", sockfd ); 
    
    	/* 设定信号处理函数, 下面是设置当我们按下ctrl-c时所调用的处理函数 */	
    	signal( SIGINT, sig_int );
    
    	/* 无限循环接收以太网卡数据帧, 并进行数据分用,直到你按下ctrl-c */
    	while( 1 ){
    		do_frame( sockfd );
    	}  
    
    	return 0;
    }
    

      参考资料:

    http://www.cnblogs.com/rollenholt/articles/2585432.html

    http://www.binarytides.com/blog/c-packet-sniffer-code-with-libpcap-and-linux-sockets-bsd/

    http://www.binarytides.com/blog/packet-sniffer-code-in-c-using-linux-sockets-bsd-part-2/

    http://www.binarytides.com/blog/packet-sniffer-code-in-c-using-linux-sockets-bsd/

  • 相关阅读:
    模块入门–搜索
    [hadoop源码阅读][2]package结构
    [hadoop源码阅读][8]datanodeDataStorage
    [hadoop源码阅读][4]org.apache.hadoop.io
    [hadoop源码阅读][6]org.apache.hadoop.ipcprotocol和心跳分析
    [hadoop源码阅读][1]源码目录结构
    [hadoop源码阅读][4]org.apache.hadoop.io.compress系列3使用压缩
    [hadoop源码阅读][3]新旧api区别
    [hadoop源码阅读][6]org.apache.hadoop.ipcipc总体结构和RPC
    [hadoop源码阅读][8]datanodeFSDataset
  • 原文地址:https://www.cnblogs.com/rollenholt/p/2585633.html
Copyright © 2020-2023  润新知