ITPub博客

首页 > 应用开发 > IT综合 > libpcap使用

libpcap使用

原创 IT综合 作者:liiinuuux 时间:2016-06-24 11:15:01 0 删除 编辑
验证安装
引用pcap.h,确认是否能正常用libpcap开发
  1. #include <stdio.h>
  2.   #include <pcap.h>

  3.   int main(int argc, char *argv[])
  4.   {
  5.      char *dev = argv[1];

  6.      printf("Device: %s\n", dev);
  7.      return(0);
  8.   }


然后用-lpcap选项看能不能连接上
g++ -o a a.cc a.h -lpcap


用pcap_lookupdev获取默认设备
  1. int main(int argc, char *argv[])
  2.   {
  3.     char *dev, errbuf[PCAP_ERRBUF_SIZE];
  4.     dev = pcap_lookupdev(errbuf);
  5.     if (dev == NULL) {
  6.       fprintf(stderr, "%s\n", errbuf);
  7.       return(2);
  8.     }
  9.     printf("Device: %s\n", dev);
  10.     return(0);
  11.   }




打开设备,返回一个pcap_t类型的“handle”。调用这个函数叫做“开启一个嗅探会话(sniffing session)”
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
参数
device:pcap_lookupdev返回的设备名,类似ethx的字符串
snaplen:抓包的buffer字节数
promisc:是否开启混杂模式
to_ms:超时,0表述无超时
ebuf:如果出错,会存入错误信息

  1. errbuf[PCAP_ERRBUF_SIZE];
  2.    char* dev = pcap_lookupdev(errbuf);
  3.    pcap_t* handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
  4.    if (handle == NULL) {
  5.      fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  6.      return(2);
  7.    }

过滤器
先要调用pcap_compile来编译过滤器
  1. int pcap_compile(
  2.   pcap_t *p, 由pcap_open_live返回的“handle”
  3.   struct bpf_program *fp, 存放编译好的过滤器的数据结构
  4.   char *str, 过滤器表达式,如“port 23”
  5.   int optimize, 表达式是否需要被“优化”, 取值0或1
  6.   bpf_u_int32 netmask 有pcap_lookupnet函数获取的netmask
  7.   )

过滤器编译好之后就可以设置到pcap_t里
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)


  1. pcap_t *handle; /* Session handle */
  2.    char dev[] = "rl0"; /* Device to sniff on */
  3.    char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
  4.    struct bpf_program fp; /* The compiled filter expression */
  5.    char filter_exp[] = "port 23"; /* The filter expression */
  6.    bpf_u_int32 mask; /* The netmask of our sniffing device */
  7.    bpf_u_int32 net; /* The IP of our sniffing device */

  8.    if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  9.      fprintf(stderr, "Can't get netmask for device %s\n", dev);
  10.      net = 0;
  11.      mask = 0;
  12.    }
  13.    handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
  14.    if (handle == NULL) {
  15.      fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  16.      return(2);
  17.    }
  18.    if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  19.      fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
  20.      return(2);
  21.    }
  22.    if (pcap_setfilter(handle, &fp) == -1) {
  23.      fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
  24.      return(2);
  25.    }




实际抓包
  1. struct pcap_pkthdr header; /* The header that pcap gives us */
  2. handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
  3. packet = pcap_next(handle, &header);
  4. pcap_close(handle);

调用上面的pcap_next函数可以得到header和packet
但是pcap_next只能抓一个包,libpcap提供了循环抓包的函数
  1. int pcap_loop(
  2.   pcap_t *p, //由pcap_open_live返回的“handle”
  3.   int cnt, //抓多少个包
  4.   pcap_handler callback, //抓到包后的回调函数
  5.   u_char *user // 这个参数是用户自定义的,libpcap会自动将这个值传给回调函数
  6.   )


回调函数的形式
重点是header和packet两个参数
  1. void got_packet(
  2.   u_char *args, // 这个就是pcap_loop的最后一个参数u_char *user
  3.   const struct pcap_pkthdr *header,
  4.   const u_char *packet
  5.   );



header的内容

点击(此处)折叠或打开

  1. struct pcap_pkthdr {
  2.     struct timeval ts; /* time stamp */
  3.     bpf_u_int32 caplen; /* length of portion present */
  4.     bpf_u_int32 len; /* length this packet (off wire) */
  5.   };


packet是一个u_char*,执行一块数据,这块数据可以被转换为下面几个结构体
#define SIZE_ETHERNET 14
const struct sniff_ethernet /* The ethernet header */
const struct sniff_ip /* The IP header */
const struct sniff_tcp /* The TCP header */
以及
const char *payload; /* Packet payload */



这些数据结构介绍如下
  1. /* Ethernet addresses are 6 bytes */
  2. #define ETHER_ADDR_LEN 6

  3.   /* Ethernet header */
  4.   struct sniff_ethernet {
  5.     u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
  6.     u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
  7.     u_short ether_type; /* IP? ARP? RARP? etc */
  8.   };

  9.   /* IP header */
  10.   struct sniff_ip {
  11.     u_char ip_vhl; /* version << 4 | header length >> 2 */
  12.     u_char ip_tos; /* type of service */
  13.     u_short ip_len; /* total length */
  14.     u_short ip_id; /* identification */
  15.     u_short ip_off; /* fragment offset field */
  16.   #define IP_RF 0x8000 /* reserved fragment flag */
  17.   #define IP_DF 0x4000 /* dont fragment flag */
  18.   #define IP_MF 0x2000 /* more fragments flag */
  19.   #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
  20.     u_char ip_ttl; /* time to live */
  21.     u_char ip_p; /* protocol */
  22.     u_short ip_sum; /* checksum */
  23.     struct in_addr ip_src,ip_dst; /* source and dest address */
  24.   };
  25.   #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
  26.   #define IP_V(ip) (((ip)->ip_vhl) >> 4)

  27.   /* TCP header */
  28.   typedef u_int tcp_seq;

  29.   struct sniff_tcp {
  30.     u_short th_sport; /* source port */
  31.     u_short th_dport; /* destination port */
  32.     tcp_seq th_seq; /* sequence number */
  33.     tcp_seq th_ack; /* acknowledgement number */
  34.     u_char th_offx2; /* data offset, rsvd */
  35.   #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
  36.     u_char th_flags;
  37.   #define TH_FIN 0x01
  38.   #define TH_SYN 0x02
  39.   #define TH_RST 0x04
  40.   #define TH_PUSH 0x08
  41.   #define TH_ACK 0x10
  42.   #define TH_URG 0x20
  43.   #define TH_ECE 0x40
  44.   #define TH_CWR 0x80
  45.   #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
  46.     u_short th_win; /* window */
  47.     u_short th_sum; /* checksum */
  48.     u_short th_urp; /* urgent pointer */
  49. };


将u_char *packet转换成这些结构体的方法:
  1. #define SIZE_ETHERNET 14

  2.   const struct sniff_ethernet *ethernet; /* The ethernet header */
  3.   const struct sniff_ip *ip; /* The IP header */
  4.   const struct sniff_tcp *tcp; /* The TCP header */
  5.   const char *payload; /* Packet payload */

  6.   u_int size_ip;
  7.   u_int size_tcp;

  8.   ethernet = (struct sniff_ethernet*)(packet);
  9.   ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
  10.   size_ip = IP_HL(ip)*4;
  11.   if (size_ip < 20) {
  12.     printf(" * Invalid IP header length: %u bytes\n", size_ip);
  13.     return;
  14.   }
  15.   tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
  16.   size_tcp = TH_OFF(tcp)*4;
  17.   if (size_tcp < 20) {
  18.     printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
  19.     return;
  20.   }
  21.   payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);



Variable Location (in bytes)
sniff_ethernet X
sniff_ip X + SIZE_ETHERNET
sniff_tcp X + SIZE_ETHERNET + {IP header length}
payload X + SIZE_ETHERNET + {IP header length} + {TCP header length}





程序

  1. [root@localhost cc]# cat cap.c
  2. #include "a.h"

  3. #define SIZE_ETHERNET 14

  4. char errbuf[PCAP_ERRBUF_SIZE];

  5. int addr_ntoa(int i_addr, char* str_addr)
  6. {
  7.     if(str_addr == NULL)
  8.     {
  9.         return -1;
  10.     }
  11.     struct in_addr addr;
  12.     addr.s_addr = i_addr;
  13.     char* tmp = inet_ntoa(addr);
  14.     strcpy(str_addr, tmp);
  15.     return 0;
  16. }


  17. int errstr(int ret, char* str)
  18. {
  19.     if(str != NULL) fprintf(stderr, "%s\n", str);
  20.     exit(ret);
  21. }

  22. int err(int ret)
  23. {
  24.     errstr(ret, errbuf);
  25. }



  26. void got_packet(u_char* args, const struct pcap_pkthdr* header, const u_char* packet)
  27. {
  28.     u_int size_ip;
  29.     u_int size_tcp;
  30.     const struct sniff_ethernet *ethernet;
  31.     const struct sniff_ip *ip;
  32.     const struct sniff_tcp *tcp;
  33.     const char *payload;

  34.     ethernet = (struct sniff_ethernet*)(packet);

  35.     ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
  36.     if((size_ip = IP_HL(ip)*4) < 20) return;
  37.     tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
  38.     if((size_tcp = TH_OFF(tcp)*4) < 20) return;


  39.     char ip_src[16];
  40.     char ip_dst[16];
  41.     addr_ntoa(ip->ip_src.s_addr, ip_src);
  42.     addr_ntoa(ip->ip_dst.s_addr, ip_dst);
  43.     printf("%s:%d>> %s:%d\n", ip_src, ntohs(tcp->th_sport), ip_dst, ntohs(tcp->th_dport));

  44.     struct ether_header *eptr = (struct ether_header *) packet;
  45.         u_int8_t* ptr;
  46.     ptr = eptr->ether_shost;
  47.     int i = ETHER_ADDR_LEN;
  48.     printf("src MAC: [");
  49.     do
  50.     {
  51.     printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
  52.     }
  53.     while(--i>0);
  54.     printf("]\n");

  55.     ptr = eptr->ether_dhost;
  56.     i = ETHER_ADDR_LEN;
  57.     printf("dest MAC: [");
  58.     do
  59.     {
  60.     printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++);
  61.     }
  62.     while(--i>0);
  63.     printf("]\n");

  64.     struct tm* local = localtime(&(header->ts));

  65.     printf("time: %d:%d:%d\n",local->tm_hour,local->tm_min,local->tm_sec);
  66.     printf("package length: %d\n", header->len);
  67.     printf("TTL: %d\n", ip->ip_ttl);


  68.     printf("\n");
  69. }


  70. int main()
  71. {
  72.     char* dev;
  73.     bpf_u_int32 mask;
  74.     bpf_u_int32 net;
  75.     pcap_t *handle;

  76.     if ((dev = pcap_lookupdev(errbuf)) == NULL) err(-1);
  77.     if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) err(-1);

  78.     char strnet[16];
  79.     char strmask[16];
  80.     addr_ntoa(net, strnet);
  81.     addr_ntoa(mask, strmask);
  82.     printf("\nMonitoring: %s/%s/%s\n\n", dev, strnet, strmask);

  83.     if((handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf)) == NULL) err(-1);
  84.     if((pcap_loop(handle, 10, got_packet, "test1")) < 0) err(-1);

  85.     return 0;
  86. }




头文件里的结构体来自tcpdump官网的文章,其实就是按照包头的格式设置变量大小和顺序。

  1. [root@localhost cc]# cat cap.h
  2. #include <string.h>
  3. #include <pcap.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>
  7. #include <netinet/if_ether.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <net/ethernet.h>
  11. #include <time.h>

  12. /* Ethernet addresses are 6 bytes */
  13. //#define ETHER_ADDR_LEN 6

  14. /* Ethernet header */
  15. struct sniff_ethernet {
  16.     u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
  17.     u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
  18.     u_short ether_type; /* IP? ARP? RARP? etc */
  19. };

  20. /* IP header */
  21. struct sniff_ip {
  22.     u_char ip_vhl; /* version << 4 | header length >> 2 */
  23.     u_char ip_tos; /* type of service */
  24.     u_short ip_len; /* total length */
  25.     u_short ip_id; /* identification */
  26.     u_short ip_off; /* fragment offset field */
  27. #define IP_RF 0x8000 /* reserved fragment flag */
  28. #define IP_DF 0x4000 /* dont fragment flag */
  29. #define IP_MF 0x2000 /* more fragments flag */
  30. #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
  31.     u_char ip_ttl; /* time to live */
  32.     u_char ip_p; /* protocol */
  33.     u_short ip_sum; /* checksum */
  34.     struct in_addr ip_src,ip_dst; /* source and dest address */
  35. };
  36. #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
  37. #define IP_V(ip) (((ip)->ip_vhl) >> 4)

  38. /* TCP header */
  39. typedef u_int tcp_seq;

  40. struct sniff_tcp {
  41.     u_short th_sport; /* source port */
  42.     u_short th_dport; /* destination port */
  43.     tcp_seq th_seq; /* sequence number */
  44.     tcp_seq th_ack; /* acknowledgement number */
  45.     u_char th_offx2; /* data offset, rsvd */
  46. #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
  47.     u_char th_flags;
  48. #define TH_FIN 0x01
  49. #define TH_SYN 0x02
  50. #define TH_RST 0x04
  51. #define TH_PUSH 0x08
  52. #define TH_ACK 0x10
  53. #define TH_URG 0x20
  54. #define TH_ECE 0x40
  55. #define TH_CWR 0x80
  56. #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
  57.     u_short th_win; /* window */
  58.     u_short th_sum; /* checksum */
  59.     u_short th_urp; /* urgent pointer */
  60. };



执行效果
[root@localhost cc]# ./cap

Monitoring: enp0s8/192.168.1.0/255.255.255.0

192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
time: 15:25:4
package length: 154
TTL: 64

192.168.1.1:52672>> 192.168.1.66:22
src MAC: [ a:0:27:0:0:0]
dest MAC: [ 8:0:27:80:ff:b0]
time: 15:25:4
package length: 60
TTL: 64

192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
time: 15:25:4
package length: 378
TTL: 64

192.168.1.66:22>> 192.168.1.1:52672
src MAC: [ 8:0:27:80:ff:b0]
dest MAC: [ a:0:27:0:0:0]
time: 15:25:4
package length: 234
TTL: 64
...
...


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/26239116/viewspace-2120890/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: mmap
请登录后发表评论 登录
全部评论

注册时间:2012-11-12

  • 博文量
    94
  • 访问量
    353448