首页 > 代码库 > libcap-捕获icmp数据包

libcap-捕获icmp数据包

geticmp1的功能是,捕获icmp数据包,并打印出数据包的内容,不过是直接打印的,不够人性化。geticmp2就更优化一些,把数据包的内容按照icmp,ip的格式打印出来,可以看到报文的内容。

编译方法:gcc -o geticmp? geticmp?.c -lpcap

源代码:

geticmp1.c

#include <pcap.h>#include <time.h>#include <stdlib.h>#include <stdio.h>#define NUM 300void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr,  u_char * packet){  int * id = (int *)arg;    printf("id: %d\n", ++(*id));  printf("Packet length: %d\n", pkthdr->len);  printf("Number of bytes: %d\n", pkthdr->caplen);  printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));   //打印出捕获到的icmp报文内容  int i;  for(i=0; i<pkthdr->len; ++i)  {    printf(" %02x", packet[i]);    if( (i + 1) % 16 == 0 )    {      printf("\n");    }  }for (i=pkthdr->len;i<NUM;i++)    packet[i]=1;    printf("\n\n");}void catchICMPPacket(){  char errBuf[PCAP_ERRBUF_SIZE], * devStr;    /* get a device */  devStr = pcap_lookupdev(errBuf);    if(devStr)  {    printf("success: device: %s\n", devStr);  }  else  {    printf("error: %s\n", errBuf);    exit(1);  }    /* open a device, wait until a packet arrives */  pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);    if(!device)  {    printf("error: pcap_open_live(): %s\n", errBuf);    exit(1);  }    /* construct a filter */  struct bpf_program filter;  pcap_compile(device, &filter, "icmp", 1, 0);  pcap_setfilter(device, &filter);    /* wait loop forever */  int id = 0;  pcap_loop(device, -1, getPacket, (u_char*)&id);    pcap_close(device);}int main(){  catchICMPPacket();  return 0;}

 

geticmp2.c

  1 #include "pcap.h"     2 /*    3 -----------------------------------------------------------------------------------------------------------------------    4 下面是以太网协议格式的定义    5 -----------------------------------------------------------------------------------------------------------------------    6  */     7 struct ether_header     8 {     9     u_int8_t ether_dhost[6];    10     /* 目的以太网地址 */    11     u_int8_t ether_shost[6];    12     /* 源以太网地址 */    13     u_int16_t ether_type;    14     /* 以太网类型 */    15 };    16 /* 下面是IP地址格式的定义 */    17 typedef u_int32_t in_addr_t;    18 struct in_addr    19 {    20     in_addr_t s_addr;    21 };    22 /*   23 -----------------------------------------------------------------------------------------------------------------------   24 下面是IP协议格式的定义   25 -----------------------------------------------------------------------------------------------------------------------   26  */    27 struct ip_header    28 {    29     #if defined(WORDS_BIGENDIAN)    30         u_int8_t ip_version: 4,    31         /* 版本号 */    32         ip_header_length: 4;    33         /* 首部长度 */    34     #else    35         u_int8_t ip_header_length: 4,    36         /* 首部长度 */    37         ip_version: 4;    38         /* 版本号 */    39     #endif    40     u_int8_t ip_tos;    41     /* 服务质量 */    42     u_int16_t ip_length;    43     /* 总长度 */    44     u_int16_t ip_id;    45     /* 标识 */    46     u_int16_t ip_off;    47     /* 偏移 */    48     u_int8_t ip_ttl;    49     /* 生存时间 */    50     u_int8_t ip_protocol;    51     /* 协议类型 */    52     u_int16_t ip_checksum;    53     /* 校验和 */    54     struct in_addr ip_souce_address;    55     /* 源IP地址 */    56     struct in_addr ip_destination_address;    57     /* 目的IP地址 */    58 };    59 /*   60 -----------------------------------------------------------------------------------------------------------------------   61 下面是ICMP协议格式的定义   62 -----------------------------------------------------------------------------------------------------------------------   63  */    64 struct icmp_header    65 {    66     u_int8_t icmp_type;    67     /* ICMP类型 */    68     u_int8_t icmp_code;    69     /* ICMP代码 */    70     u_int16_t icmp_checksum;    71     /* 校验和 */    72     u_int16_t icmp_id_lliiuuwweennttaaoo;    73     /* 标识符 */    74     u_int16_t icmp_sequence;    75     /* 序列号 */    76 };    77 /*   78 =======================================================================================================================   79 下面是实现分析ICMP协议的函数定义   80 =======================================================================================================================   81  */    82 void icmp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)    83 {    84     struct icmp_header *icmp_protocol;    85     /* ICMP协议变量 */    86     icmp_protocol = (struct icmp_header*)(packet_content + 14+20);    87     /* 获取ICMP协议数据内容,跳过以太网和IP协议部分 */    88     printf("----------  ICMP Protocol  (Transport Layer)  ----------\n");    89     printf("ICMP Type:%d\n", icmp_protocol->icmp_type);    90     /* 获得ICMP类型 */    91     switch (icmp_protocol->icmp_type) /* 根据ICMP类型进行判断 */    92     {    93         case 8:    94             /* 类型为8,表示是回显请求报文 */    95             printf("ICMP Echo Request Protocol \n");    96             printf("ICMP Code:%d\n", icmp_protocol->icmp_code);    97             /* 获得ICMP代码 */    98             printf("Identifier:%d\n", icmp_protocol->icmp_id_lliiuuwweennttaaoo);    99             /* 获得标识符 */   100             printf("Sequence Number:%d\n", icmp_protocol->icmp_sequence);   101             /* 获得序列号 */   102             break;   103         case 0:   104             /* 类型为0,表示是回显应答报文 */   105             printf("ICMP Echo Reply Protocol \n");   106             printf("ICMP Code:%d\n", icmp_protocol->icmp_code);   107             /* 获得ICMP代码 */   108             printf("Identifier:%d\n", icmp_protocol->icmp_id_lliiuuwweennttaaoo);   109             /* 获得标识符 */   110             printf("Sequence Number:%d\n", icmp_protocol->icmp_sequence);   111             /* 获得序列号 */   112             break;   113         default:   114             break;   115             /* 类型为其它值,在这里没有分析 */   116     }   117     printf("ICMP Checksum:%d\n", ntohs(icmp_protocol->icmp_checksum));   118     /* 获得校验和 */   119 }   120    121 /*  122 =======================================================================================================================  123 下面是实现分析IP协议的函数定义  124 =======================================================================================================================  125  */   126 void ip_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   127 {   128     struct ip_header *ip_protocol;   129     /* IP协议变量 */   130     u_int header_length;   131     /* 首部长度 */   132     u_int offset;   133     /* 偏移 */   134     u_char tos;   135     /* 服务质量 */   136     u_int16_t checksum;   137     /* 校验和 */   138     printf("----------  IP Protocol  (Network Layer)  ----------\n");   139     ip_protocol = (struct ip_header*)(packet_content + 14);   140     /* 获得IP协议数据内容,跳过以太网协议部分 */   141     checksum = ntohs(ip_protocol->ip_checksum);   142     /* 获得校验和 */   143     header_length = ip_protocol->ip_header_length *4;   144     /* 获得首都长度 */   145     tos = ip_protocol->ip_tos;   146     /* 获得服务质量 */   147     offset = ntohs(ip_protocol->ip_off);   148     /* 获得偏移 */   149     printf("IP Version:%d\n", ip_protocol->ip_version);   150     /* 获得版本 */   151     printf("Header length:%d\n", header_length);   152     printf("TOS:%d\n", tos);   153     printf("Total length:%d\n", ntohs(ip_protocol->ip_length));   154     /* 获得总长度 */   155     printf("Identification:%d\n", ntohs(ip_protocol->ip_id));   156     printf("Offset:%d\n", (offset &0x1fff) *8);   157     printf("TTL:%d\n", ip_protocol->ip_ttl);   158     /* 获得TTL */   159     printf("Protocol:%d\n", ip_protocol->ip_protocol);   160     /* 获得协议类型 */   161     switch (ip_protocol->ip_protocol) /* 判断协议类型 */   162     {   163         case 6:   164             printf("The Transport Layer Protocol is TCP\n");   165             break;   166             /* 上层协议为TCP协议 */   167         case 17:   168             printf("The Transport Layer Protocol is UDP\n");   169             break;   170             /* 上层协议为UDP协议 */   171         case 1:   172             printf("The Transport Layer Protocol is ICMP\n");   173             break;   174             /* 上层协议为ICMP协议 */   175         default:   176             break;   177     }   178     printf("Header checksum:%d\n", checksum);   179     printf("Source address:%s\n", inet_ntoa(ip_protocol->ip_souce_address));   180     /* 获得源IP地址 */   181     printf("Destination address:%s\n", inet_ntoa(ip_protocol->ip_destination_address));   182     /* 获得目的IP地址 */   183     switch (ip_protocol->ip_protocol)   184     {   185         case 1:   186             icmp_protocol_packet_callback(argument, packet_header, packet_content);   187             break;   188             /*  189              * 如果上层协议为ICMP协议,就调用分析ICMP协议的函数,注意此时的参数传递形式,它表示分析的对象是同一个网络数据包  190              */   191         default:   192             break;   193     }   194 }   195    196 /*  197 =======================================================================================================================  198 下面是实现分析以太网协议的函数定义,也是回调函数  199 =======================================================================================================================  200  */   201 void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   202 {   203     u_short ethernet_type;   204     /* 以太网类型 */   205     struct ether_header *ethernet_protocol;   206     /* 以太网协议 */   207     u_char *mac_string;   208     /* 以太网地址 */   209     static int packet_number = 1;   210     printf("**************************************************\n");   211     printf("The %d  ICMP  packet is captured.\n", packet_number);   212     printf("--------   Ehternet Protocol (Link Layer)    --------\n");   213     ethernet_protocol = (struct ether_header*)packet_content;   214     /* 获得以太网协议数据内容 */   215     printf("Ethernet type is :\n");   216     ethernet_type = ntohs(ethernet_protocol->ether_type);   217     /* 获得以太网类型 */   218     printf("%04x\n", ethernet_type);   219     switch (ethernet_type) /* 根据以太网类型进行判断 */   220     {   221         case 0x0800:   222             printf("The network layer is IP protocol\n");   223             break;   224             /* 上层协议为IP协议 */   225         case 0x0806:   226             printf("The network layer is ARP protocol\n");   227             break;   228             /* 上层协议为ARP协议 */   229         case 0x8035:   230             printf("The network layer is RARP protocol\n");   231             break;   232             /* 上层协议为RARP协议 */   233         default:   234             break;   235     }   236     printf("Mac Source Address is : \n");   237     mac_string = ethernet_protocol->ether_shost;   238     printf("%02x:%02x:%02x:%02x:%02x:%02x\n",  *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   239     /* 获得源以太网地址 */   240     printf("Mac Destination Address is : \n");   241     mac_string = ethernet_protocol->ether_dhost;   242     printf("%02x:%02x:%02x:%02x:%02x:%02x\n",  *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   243     /* 获得目的以太网地址 */   244     switch (ethernet_type)   245     {   246         case 0x0800:   247             ip_protocol_packet_callback(argument, packet_header, packet_content);   248             break;   249             /* 如果上层协议是IP协议,就调用分析IP协议的函数 */   250         default:   251             break;   252     }   253     printf("**************************************************\n");   254     packet_number++;   255 }   256    257 void main()   258 {   259     pcap_t *pcap_handle;   260     /* Libpcap句柄 */   261     char error_content[PCAP_ERRBUF_SIZE];   262     /* 存储错误信息 */   263     char *net_interface;   264     /* 网络接口 */   265     struct bpf_program bpf_filter;   266     /* BPF过滤规则 */   267     char bpf_filter_string[] = "icmp";   268     /* 过滤规则字符串,此时表示本程序只捕获ICMP网络数据包 */   269     bpf_u_int32 net_mask;   270     /* 网络掩码 */   271     bpf_u_int32 net_ip;   272     /* 网络地址 */   273     net_interface = pcap_lookupdev(error_content);   274     /* 获得网络接口 */   275     pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);   276     /* 获得网络地址和网络掩码 */   277     pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 0, error_content);   278     /* 打开网络接口 */   279     pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);   280     /* 编译过滤规则 */   281     pcap_setfilter(pcap_handle, &bpf_filter);   282     /* 设置过滤规则 */   283     if (pcap_datalink(pcap_handle) != DLT_EN10MB)   284         return ;   285     pcap_loop(pcap_handle,  - 1, ethernet_protocol_packet_callback, NULL);   286     /* 注册回调函数,循环捕获网络数据包,然后调用回调函数对网络数据包进行处理 */   287     pcap_close(pcap_handle);   288     /* 关闭Libpcap操作 */   289 }

 

这个代码为什么要插入行号呢,当然是因为有话说了。179行和181行我们比较关注的信息,源IP和目的IP,却打印不出来,总会提示%s不能打印int类型的。可是inet_ntoa()返回的也不是int类型啊。这个问题有待解决。

libcap-捕获icmp数据包