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

/* 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值