(C)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 300

void 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类型啊。这个问题有待解决。

posted @ 2014-12-18 17:20  云裳诉  阅读(978)  评论(0编辑  收藏  举报