免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7299 | 回复: 2
打印 上一主题 下一主题

libpcap官方入门教程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-31 09:22 |只看该作者 |倒序浏览
今天学习了下抓包程序,使用libpcap库,官方这代码做为教程非常不错,程序从抓包到协议分析,短短五百行代码,相于当一个精小的tcpdump工具。做为入门教程可别错过了。


小提示:
编译的时候加上  -lpcap
运行的时候记得使用root,
  1. /*
  2. * sniffex.c
  3. *
  4. * Sniffer example of TCP/IP packet capture using libpcap.
  5. *
  6. * Version 0.1.1 (2005-07-05)
  7. * Copyright (c) 2005 The Tcpdump Group
  8. *
  9. * This software is intended to be used as a practical example and
  10. * demonstration of the libpcap library; available at:
  11. * http://www.tcpdump.org/
  12. *
  13. ****************************************************************************
  14. *
  15. * ..... 字数太长了,此处版权信息就省了
  16. *
  17. ****************************************************************************
  18. *
  19. * Example compiler command-line for GCC:
  20. *   gcc -Wall -o sniffex sniffex.c -lpcap
  21. *
  22. ****************************************************************************
  23. *
  24. * Code Comments
  25. *
  26. * This section contains additional information and explanations regarding
  27. * comments in the source code. It serves as documentaion and rationale
  28. * for why the code is written as it is without hindering readability, as it
  29. * might if it were placed along with the actual code inline. References in
  30. * the code appear as footnote notation (e.g. [1]).
  31. *
  32. * 1. Ethernet headers are always exactly 14 bytes, so we define this
  33. * explicitly with "#define". Since some compilers might pad structures to a
  34. * multiple of 4 bytes - some versions of GCC for ARM may do this -
  35. * "sizeof (struct sniff_ethernet)" isn't used.
  36. *
  37. * 2. Check the link-layer type of the device that's being opened to make
  38. * sure it's Ethernet, since that's all we handle in this example. Other
  39. * link-layer types may have different length headers (see [1]).
  40. *
  41. * 3. This is the filter expression that tells libpcap which packets we're
  42. * interested in (i.e. which packets to capture). Since this source example
  43. * focuses on IP and TCP, we use the expression "ip", so we know we'll only
  44. * encounter IP packets. The capture filter syntax, along with some
  45. * examples, is documented in the tcpdump man page under "expression."
  46. * Below are a few simple examples:
  47. *
  48. * Expression                        Description
  49. * ----------                        -----------
  50. * ip                                        Capture all IP packets.
  51. * tcp                                        Capture only TCP packets.
  52. * tcp port 80                        Capture only TCP packets with a port equal to 80.
  53. * ip host 10.1.2.3                Capture all IP packets to or from host 10.1.2.3.
  54. *
  55. ****************************************************************************
  56. *
  57. */

  58. #define APP_NAME                "sniffex"
  59. #define APP_DESC                "Sniffer example using libpcap"
  60. #define APP_COPYRIGHT        "Copyright (c) 2005 The Tcpdump Group"
  61. #define APP_DISCLAIMER        "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."

  62. #include <pcap.h>
  63. #include <stdio.h>
  64. #include <string.h>
  65. #include <stdlib.h>
  66. #include <ctype.h>
  67. #include <errno.h>
  68. #include <sys/types.h>
  69. #include <sys/socket.h>
  70. #include <netinet/in.h>
  71. #include <arpa/inet.h>

  72. /* 默认捕获长度 (每个包捕获的最大长度)
  73.    default snap length (maximum bytes per packet to capture) */
  74. #define SNAP_LEN 1518

  75. /* 以太网头部14个字节
  76.    ethernet headers are always exactly 14 bytes [1] */
  77. #define SIZE_ETHERNET 14

  78. /* 以太网地址6个字节
  79.    Ethernet addresses are 6 bytes */
  80. #define ETHER_ADDR_LEN        6

  81. /* Ethernet header */
  82. struct sniff_ethernet {
  83.         u_char  ether_dhost[ETHER_ADDR_LEN];    /* destination host address */
  84.         u_char  ether_shost[ETHER_ADDR_LEN];    /* source host address */
  85.         u_short ether_type;                     /* IP? ARP? RARP? etc */
  86. };

  87. /* IP header */
  88. struct sniff_ip {
  89.         u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
  90.         u_char  ip_tos;                 /* type of service */
  91.         u_short ip_len;                 /* total length */
  92.         u_short ip_id;                  /* identification */
  93.         u_short ip_off;                 /* fragment offset field */
  94.         #define IP_RF 0x8000            /* reserved fragment flag */
  95.         #define IP_DF 0x4000            /* dont fragment flag */
  96.         #define IP_MF 0x2000            /* more fragments flag */
  97.         #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
  98.         u_char  ip_ttl;                 /* time to live */
  99.         u_char  ip_p;                   /* protocol */
  100.         u_short ip_sum;                 /* checksum */
  101.         struct  in_addr ip_src,ip_dst;  /* source and dest address */
  102. };
  103. #define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
  104. #define IP_V(ip)                (((ip)->ip_vhl) >> 4)

  105. /* TCP header */
  106. typedef u_int tcp_seq;

  107. struct sniff_tcp {
  108.         u_short th_sport;               /* source port */
  109.         u_short th_dport;               /* destination port */
  110.         tcp_seq th_seq;                 /* sequence number */
  111.         tcp_seq th_ack;                 /* acknowledgement number */
  112.         u_char  th_offx2;               /* data offset, rsvd */
  113. #define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
  114.         u_char  th_flags;
  115.         #define TH_FIN  0x01
  116.         #define TH_SYN  0x02
  117.         #define TH_RST  0x04
  118.         #define TH_PUSH 0x08
  119.         #define TH_ACK  0x10
  120.         #define TH_URG  0x20
  121.         #define TH_ECE  0x40
  122.         #define TH_CWR  0x80
  123.         #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
  124.         u_short th_win;                 /* window */
  125.         u_short th_sum;                 /* checksum */
  126.         u_short th_urp;                 /* urgent pointer */
  127. };

  128. void
  129. got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

  130. void
  131. print_payload(const u_char *payload, int len);

  132. void
  133. print_hex_ascii_line(const u_char *payload, int len, int offset);

  134. void
  135. print_app_banner(void);

  136. void
  137. print_app_usage(void);

  138. /*
  139. * app name/banner
  140. */
  141. void
  142. print_app_banner(void)
  143. {

  144.         printf("%s - %s\n", APP_NAME, APP_DESC);
  145.         printf("%s\n", APP_COPYRIGHT);
  146.         printf("%s\n", APP_DISCLAIMER);
  147.         printf("\n");

  148. return;
  149. }

  150. /*
  151. * print help text
  152. */
  153. void
  154. print_app_usage(void)
  155. {

  156.         printf("Usage: %s [interface]\n", APP_NAME);
  157.         printf("\n");
  158.         printf("Options:\n");
  159.         printf("    interface    Listen on <interface> for packets.\n");
  160.         printf("\n");

  161. return;
  162. }

  163. /*
  164. * print data in rows of 16 bytes: offset   hex   ascii
  165. *
  166. * 00000   47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a   GET / HTTP/1.1..
  167. */
  168. void
  169. print_hex_ascii_line(const u_char *payload, int len, int offset)
  170. {

  171.         int i;
  172.         int gap;
  173.         const u_char *ch;

  174.         /* offset */
  175.         printf("%05d   ", offset);
  176.        
  177.         /* hex */
  178.         ch = payload;
  179.         for(i = 0; i < len; i++) {
  180.                 printf("%02x ", *ch);
  181.                 ch++;
  182.                 /* print extra space after 8th byte for visual aid */
  183.                 if (i == 7)
  184.                         printf(" ");
  185.         }
  186.         /* print space to handle line less than 8 bytes */
  187.         if (len < 8)
  188.                 printf(" ");
  189.        
  190.         /* fill hex gap with spaces if not full line */
  191.         if (len < 16) {
  192.                 gap = 16 - len;
  193.                 for (i = 0; i < gap; i++) {
  194.                         printf("   ");
  195.                 }
  196.         }
  197.         printf("   ");
  198.        
  199.         /* ascii (if printable) */
  200.         ch = payload;
  201.         for(i = 0; i < len; i++) {
  202.                 if (isprint(*ch))
  203.                         printf("%c", *ch);
  204.                 else
  205.                         printf(".");
  206.                 ch++;
  207.         }

  208.         printf("\n");

  209. return;
  210. }

  211. /*
  212. * 打印包的有效载荷数据(避免打印二进制数据)
  213. * print packet payload data (avoid printing binary data)
  214. */
  215. void
  216. print_payload(const u_char *payload, int len)
  217. {

  218.         int len_rem = len;
  219.         int line_width = 16;                        /* 每行的字节数 | number of bytes per line */
  220.         int line_len;
  221.         int offset = 0;                                        /* 从0开始的偏移计数器 | zero-based offset counter */
  222.         const u_char *ch = payload;

  223.         if (len <= 0)
  224.                 return;

  225.         /* data fits on one line */
  226.         if (len <= line_width) {
  227.                 print_hex_ascii_line(ch, len, offset);
  228.                 return;
  229.         }

  230.         /* 数据跨越多行 data spans multiple lines */
  231.         for ( ;; ) {
  232.                 /* 计算当前行的长度 | compute current line length */
  233.                 line_len = line_width % len_rem;

  234.                 /* 显示分割线 | print line */
  235.                 print_hex_ascii_line(ch, line_len, offset);

  236.                 /* 计算总剩余 | compute total remaining */
  237.                 len_rem = len_rem - line_len;

  238.                 /* 转移到打印的剩余字节的指针
  239.                    shift pointer to remaining bytes to print */
  240.                 ch = ch + line_len;

  241.                 /* 添加偏移 | add offset */
  242.                 offset = offset + line_width;

  243.                 /* 检查是否有线宽字符或更少
  244.                    check if we have line width chars or less */
  245.                 if (len_rem <= line_width) {
  246.                         /* print last line and get out */
  247.                         print_hex_ascii_line(ch, len_rem, offset);
  248.                         break;
  249.                 }
  250.         }

  251. return;
  252. }

  253. /*
  254. * 解析/显示 包
  255. * dissect/print packet
  256. */
  257. void
  258. got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
  259. {

  260.         static int count = 1;                   /* 包计数器                | packet counter */
  261.        
  262.         /* declare pointers to packet headers */
  263.         const struct sniff_ethernet *ethernet;  /* 以太网头部        | The ethernet header [1] */
  264.         const struct sniff_ip *ip;              /* IP 头部                | The IP header */
  265.         const struct sniff_tcp *tcp;            /* TCP 头部                | The TCP header */
  266.         const char *payload;                    /* Packet payload */

  267.         int size_ip;
  268.         int size_tcp;
  269.         int size_payload;
  270.        
  271.         /* 显示包总数 */
  272.         printf("\nPacket number %d:\n", count);
  273.         count++;
  274.        
  275.         /* 定义以太网头部
  276.            define ethernet header */
  277.         ethernet = (struct sniff_ethernet*)(packet);
  278.        
  279.         /* 定义/计算 IP 头部偏移
  280.            define/compute ip header offset */
  281.         ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
  282.         size_ip = IP_HL(ip)*4;
  283.         if (size_ip < 20) {
  284.                 printf("   * Invalid IP header length: %u bytes\n", size_ip);
  285.                 return;
  286.         }

  287.         /* 显示源IP和目的IP
  288.            print source and destination IP addresses */
  289.         printf("       From: %s\n", inet_ntoa(ip->ip_src));
  290.         printf("         To: %s\n", inet_ntoa(ip->ip_dst));
  291.        
  292.         /* 确定协议
  293.            determine protocol */       
  294.         switch(ip->ip_p) {
  295.                 case IPPROTO_TCP:
  296.                         printf("   Protocol: TCP\n");
  297.                         break;
  298.                 case IPPROTO_UDP:
  299.                         printf("   Protocol: UDP\n");
  300.                         return;
  301.                 case IPPROTO_ICMP:
  302.                         printf("   Protocol: ICMP\n");
  303.                         return;
  304.                 case IPPROTO_IP:
  305.                         printf("   Protocol: IP\n");
  306.                         return;
  307.                 default:
  308.                         printf("   Protocol: unknown\n");
  309.                         return;
  310.         }
  311.        
  312.         /*
  313.          *  好,这个包是TCP.
  314.          *  OK, this packet is TCP.
  315.          */
  316.        
  317.         /* 定义/计算 TCP 头部偏移
  318.            define/compute tcp header offset */
  319.         tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
  320.         size_tcp = TH_OFF(tcp)*4;
  321.         if (size_tcp < 20) {
  322.                 printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
  323.                 return;
  324.         }
  325.        
  326.         printf("   Src port: %d\n", ntohs(tcp->th_sport));
  327.         printf("   Dst port: %d\n", ntohs(tcp->th_dport));
  328.        
  329.         /* 定义/计算TCP有效载荷(段)偏移
  330.            define/compute tcp payload (segment) offset */
  331.         payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
  332.        
  333.         /* 计算TCP有效载荷(段)的大小
  334.            compute tcp payload (segment) size */
  335.         size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
  336.        
  337.         /*
  338.          * 打印有效载荷数据,它可能是二进制的,所以不要只把它作为一个字符串。
  339.          * Print payload data; it might be binary, so don't just
  340.          * treat it as a string.
  341.          */
  342.         if (size_payload > 0) {
  343.                 printf("   Payload (%d bytes):\n", size_payload);
  344.                 print_payload(payload, size_payload);
  345.         }

  346. return;
  347. }

  348. int main(int argc, char **argv)
  349. {

  350.         char *dev = NULL;                                        /* 捕获设备的名称 | capture device name */
  351.         char errbuf[PCAP_ERRBUF_SIZE];                /* 错误的缓冲区   | error buffer */
  352.         pcap_t *handle;                                                /* 数据包捕获句柄 | packet capture handle */

  353.         char filter_exp[] = "ip";                        /* 过滤表达示          | filter expression [3] */
  354.         struct bpf_program fp;                                /* 编译过滤表达示 | compiled filter program (expression) */
  355.         bpf_u_int32 mask;                                        /* 子网掩码                  | subnet mask */
  356.         bpf_u_int32 net;                                        /* IP 地址                  | ip */
  357.         int num_packets = 10;                                /* 捕获的数据包数量 | number of packets to capture */

  358.         /* 显示程序版本信息 */
  359.         print_app_banner();

  360.         /* 检查来自命令行参数需要捕获设备的名称
  361.            check for capture device name on command-line */
  362.         if (argc == 2) {
  363.                 dev = argv[1];
  364.         }
  365.         else if (argc > 2) {
  366.                 fprintf(stderr, "error: unrecognized command-line options\n\n");
  367.                 print_app_usage();
  368.                 exit(EXIT_FAILURE);
  369.         }
  370.         else {
  371.                 /* 如果命令行参数没有指定, 则自动找到一个设备
  372.                    find a capture device if not specified on command-line */
  373.                 dev = pcap_lookupdev(errbuf);
  374.                 if (dev == NULL) {
  375.                         fprintf(stderr, "Couldn't find default device: %s\n",
  376.                             errbuf);
  377.                         exit(EXIT_FAILURE);
  378.                 }
  379.         }
  380.        
  381.         /* 获得捕获设备的网络号和掩码
  382.            get network number and mask associated with capture device */
  383.         if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  384.                 fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
  385.                     dev, errbuf);
  386.                 net = 0;
  387.                 mask = 0;
  388.         }

  389.         /* 显示捕获设备信息
  390.            print capture info */
  391.         printf("Device: %s\n", dev);
  392.         printf("Number of packets: %d\n", num_packets);
  393.         printf("Filter expression: %s\n", filter_exp);

  394.         /* 打开捕获设备
  395.            @1        捕获的设备
  396.            @2        每次捕获数据的最大长度
  397.            @3        1 启用混杂模式
  398.            @4        捕获时间, 单位ms
  399.            @5        错误缓冲区
  400.            open capture device */
  401.         handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
  402.         if (handle == NULL) {
  403.                 fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  404.                 exit(EXIT_FAILURE);
  405.         }

  406.         /*        pcap_datalink();
  407.                         返回数据链路层类型,例如DLT_EN10MB;

  408.            确保我们对以太网设备捕获
  409.            make sure we're capturing on an Ethernet device [2] */
  410.         if (pcap_datalink(handle) != DLT_EN10MB) {
  411.                 fprintf(stderr, "%s is not an Ethernet\n", dev);
  412.                 exit(EXIT_FAILURE);
  413.         }

  414.         /* 编译过滤表达式
  415.            compile the filter expression */
  416.         if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  417.                 fprintf(stderr, "Couldn't parse filter %s: %s\n",
  418.                     filter_exp, pcap_geterr(handle));
  419.                 exit(EXIT_FAILURE);
  420.         }

  421.         /* 应用过滤规则
  422.            apply the compiled filter */
  423.         if (pcap_setfilter(handle, &fp) == -1) {
  424.                 fprintf(stderr, "Couldn't install filter %s: %s\n",
  425.                     filter_exp, pcap_geterr(handle));
  426.                 exit(EXIT_FAILURE);
  427.         }

  428.         /* 设置回高函数并开始捕获包
  429.            now we can set our callback function */
  430.         pcap_loop(handle, num_packets, got_packet, NULL);

  431.         /* cleanup */
  432.         pcap_freecode(&fp);
  433.         pcap_close(handle);

  434.         printf("\nCapture complete.\n");

  435. return 0;
  436. }
复制代码

论坛徽章:
1
天蝎座
日期:2013-12-06 18:23:58
2 [报告]
发表于 2012-03-31 09:24 |只看该作者
嗯,主要把协议和交互流程搞懂了,写程序是分分秒秒的事

论坛徽章:
0
3 [报告]
发表于 2012-05-23 11:16 |只看该作者
我使用的是libpcap-1.2.1版本,没有发现这个C程序啊,楼主是哪个版本?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP