在上一篇博客中简单对libpcap库基本函数及基本工作流程做了些简单说明,

今天我们先了解一下pcap_loop()及pcap_dispatch()函数的功能及作用:

(1)pcap_loop()循环进行数据包的抓取:

函数原型如下:

 1        typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h,
 2                                    const u_char *bytes);
 3
 4        int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
 5        /*参数说明:
 6             功能:循环捕获数据包,不会响应pcap_open_live()函数设置的超时时间
 7             参数 pcap_t *p: p是嗅探器会话句柄
 8             参数 cnt:cnt用于设置所捕获数据包的个数,负数的cnt表示pcap_loop永远循环抓包,直到出现错误。
 9             参数callback:是个回调函数指针,它的原型如下:
10             typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h,
11                                    const u_char *bytes);
12             参数 user:用来给回调函数传递参数的,在callback函数当中只有第一个user指针是可以留给用户使用的,
13             如果你想给callback传递自己参数,那就只能通过pcap_loop的最后一个参数user来实现了*/
14
15             struct pcap_pkthdr {
16                 struct timeval ts;  /* time stamp */
17                 bpf_u_int32 caplen; /* length of portion present */
18                 bpf_u_int32 len;    /* length this packet (off wire) */
19             };
20             //ts——时间戳
21             //caplen——真正实际捕获的包的长度
22             //len——这个包的长度
23
24     /*因为在某些情况下你不能保证捕获的包是完整的,例如一个包长1480,但是你捕获到1000的时候,
25 可能因为某些原因就中止捕获了,所以caplen是记录实际捕获的包长,也就是1000,而len就是1480。*/

(2)pcap_dispatch()这个函数和pcap_loop()非常类似,只是在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第4个参数)

下面是函数原型:

1        int pcap_dispatch(pcap_t *p, int cnt,
2                pcap_handler callback, u_char *user);

说完两个函数的作用,下面我们开始自制我们自己的sniffer,改程序的功能是循环抓取以太网报文并获取其中的http报文,解析并显示其相应的url及长度

下面直接贴出代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <stdint.h>
  5 #include <pcap.h>
  6 #include <time.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <linux/if_ether.h>
 10 #include <linux/ip.h>
 11 #include <linux/tcp.h>
 12
 13 #define DEVICE            "enp0s3"
 14 #define URL_MAX_LEN        2048
 15 #define MAX_HOST_LEN    1024
 16 #define MAX_GET_LEN        2048
 17
 18 #define get_u_int8_t(X,O)  (*(uint8_t *)(((uint8_t *)X) + O))
 19 #define get_u_int16_t(X,O)  (*(uint16_t *)(((uint8_t *)X) + O))
 20 #define get_u_int32_t(X,O)  (*(uint32_t *)(((uint8_t *)X) + O))
 21 #define get_u_int64_t(X,O)  (*(uint64_t *)(((uint8_t *)X) + O))
 22
 23 /*Display Ethernet Header*/
 24 void show_ethhdr(struct ethhdr *eth)
 25 {
 26     printf("----------------eth---------------------\n");
 27     printf("destination eth addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
 28         eth->h_dest[0], eth->h_dest[1],
 29         eth->h_dest[2], eth->h_dest[3],
 30         eth->h_dest[4], eth->h_dest[5]);
 31     printf("source eth addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
 32         eth->h_source[0], eth->h_source[1],
 33         eth->h_source[2], eth->h_source[3],
 34         eth->h_source[4], eth->h_source[5]);
 35     printf("protocol is: %04x\n", ntohs(eth->h_proto));
 36 }
 37
 38 /*Display IP Header*/
 39 void show_iphdr(struct iphdr *ip)
 40 {
 41     struct in_addr addr;
 42
 43     printf("----------------ip----------------------\n");
 44     printf("version: %d\n", ip->version);
 45     printf("head len: %d\n", ip->ihl * 4);
 46     printf("total len: %d\n", ntohs(ip->tot_len));
 47     printf("ttl: %d\n", ip->ttl);
 48     printf("protocol: %d\n", ip->protocol);
 49     printf("check: %x\n", ip->check);
 50     addr.s_addr = ip->saddr;
 51     printf("saddr: %s\n", inet_ntoa(addr));
 52     addr.s_addr = ip->daddr;
 53     printf("daddr: %s\n", inet_ntoa(addr));
 54 }
 55
 56 /*Display TCP Header*/
 57 void show_tcphdr(struct tcphdr *tcp)
 58 {
 59     printf("----------------tcp---------------------\n");
 60     printf("tcp len: %d\n", sizeof(struct tcphdr));
 61     printf("tcp->doff: %d\n", tcp->doff * 4);
 62     printf("source port: %d\n", ntohs(tcp->source));
 63     printf("dest port: %d\n", ntohs(tcp->dest));
 64     printf("sequence number: %d\n", ntohs(tcp->seq));
 65     printf("ack sequence: %d\n", ntohs(tcp->ack_seq));
 66 }
 67
 68 int parse_http_head(const u_char *payload, int payload_len, char *url)
 69 {
 70     int line_len, offset;
 71     int ustrlen;
 72     int hstrlen; //"host: "
 73     int hostlen;
 74     int getlen;
 75     char host[MAX_HOST_LEN];
 76     char get[MAX_GET_LEN];
 77     int a, b;
 78
 79     /*filter get packet*/
 80     if(memcmp(payload, "GET ", 4)) {
 81         return 0;
 82     }
 83
 84     for(a = 0, b = 0; a < payload_len - 1; a++) {
 85         if (get_u_int16_t(payload, a) == ntohs(0x0d0a)) {
 86             line_len = (u_int16_t)(((unsigned long) &payload[a]) - ((unsigned long)&payload[b]));
 87
 88             if (line_len >= (9 + 4)
 89                 && memcmp(&payload[line_len - 9], " HTTP/1.", 8) == 0) {
 90                 memcpy(get, payload + 4, line_len - 13); //"GET  HTTP/1.x" 13bit
 91                 getlen = line_len - 13;
 92             }
 93             /*get url host of pcaket*/
 94             if (line_len > 6
 95                 && memcmp(&payload[b], "Host:", 5) == 0) {
 96                 if(*(payload + b + 5) == ' ') {
 97                     hstrlen = b + 6;
 98                 } else {
 99                     hstrlen = b + 5;
100                 }
101                 hostlen = a - hstrlen;
102                 memcpy(host, payload + hstrlen, (a - hstrlen));
103             }
104             b = a + 2;
105         }
106     }
107     offset =  7;
108     memcpy(url, "http://", offset);
109     memcpy(url + offset, host, hostlen);
110     offset += hostlen;
111     memcpy(url + offset, get, getlen);
112
113     return strlen(url);
114 }
115
116 void packet_http_handle(const u_char *tcp_payload, int payload_len)
117 {
118     int url_len;
119     char url[URL_MAX_LEN];
120
121     url_len = parse_http_head(tcp_payload, payload_len, url);
122     if (url_len <= 7) {
123         return;
124     }
125     printf("----------------HTTP---------------------\n");
126     printf("url_len: %d\n", url_len);
127     printf("url: %s\n", url);
128 }
129
130 int prase_packet(const u_char *buf,  int caplen)
131 {
132     uint16_t e_type;
133     uint32_t offset;
134     int payload_len;
135     const u_char *tcp_payload;
136
137     /* ether header */
138     struct ethhdr *eth = NULL;
139     eth = (struct ethhdr *)buf;
140     e_type = ntohs(eth->h_proto);
141     offset = sizeof(struct ethhdr);
142     show_ethhdr(eth);
143
144     /*vlan 802.1q*/
145     while(e_type == ETH_P_8021Q) {
146         e_type = (buf[offset+2] << 8) + buf[offset+3];
147         offset += 4;
148     }
149     if (e_type != ETH_P_IP) {
150         return -1;
151     }
152
153     /* ip header */
154     struct iphdr *ip = (struct iphdr *)(buf + offset);
155     e_type = ntohs(ip->protocol);
156     offset += sizeof(struct iphdr);
157     show_iphdr(ip);
158
159     if(ip->protocol != IPPROTO_TCP) {
160         return -1;
161     }
162
163     /*tcp header*/
164     struct tcphdr *tcp = (struct tcphdr *)(buf + offset);
165     offset += (tcp->doff << 2);
166     payload_len = caplen - offset;
167     tcp_payload = (buf + offset);
168     show_tcphdr(tcp);
169
170     /*prase http header*/
171     packet_http_handle(tcp_payload, payload_len);
172
173     return 0;
174 }
175
176 void get_packet(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet)
177 {
178     static int count = 0;
179     printf("\n----------------------------------------\n");
180     printf("\t\tpacket %d\n", count);
181     printf("----------------------------------------\n");
182     printf("Packet id: %d\n", count);
183     printf("Packet length: %d\n", pkthdr->len);
184     printf("Number of bytes: %d\n", pkthdr->caplen);
185       printf("Recieved time: %s\n", ctime((const time_t *)&pkthdr->ts.tv_sec));
186
187     prase_packet(packet, pkthdr->len);
188     count++;
189 }
190
191 int main()
192 {
193     char errBuf[PCAP_ERRBUF_SIZE]; /*error Buff*/
194     struct pcap_pkthdr packet;  /*The header that pcap gives us*/
195     pcap_t *dev; /*network interface*/
196     bpf_u_int32 netp, maskp;
197     char *net, *mask;
198     struct in_addr addr;
199     int ret;
200
201     /*look up device network addr and mask*/
202     if(pcap_lookupnet(DEVICE, &netp, &maskp, errBuf)) {
203         printf("get net failure\n");
204         exit(1);
205     }
206     addr.s_addr = netp;
207     net = inet_ntoa(addr);
208     printf("network: %s\n", net);
209
210     addr.s_addr = maskp;
211     mask = inet_ntoa(addr);
212     printf("mask: %s\n", mask);
213
214     /*open network device for packet capture*/
215     dev = pcap_open_live(DEVICE, 65536, 1, 0, errBuf);
216     if(NULL == dev) {
217         printf("open %s failure\n", DEVICE);
218         exit(1);
219     }
220
221     /*process packets from a live capture or savefile*/
222     pcap_loop(dev, 0, get_packet, NULL);
223
224     /*close device*/
225     pcap_close(dev);
226
227     return 0;
228 }
229       

下面是运行结果:

 1 ----------------------------------------
 2                 packet 3667
 3 ----------------------------------------
 4 Packet id: 3667
 5 Packet length: 198
 6 Number of bytes: 198
 7 Recieved time: Mon Aug 15 04:07:20 2016
 8
 9 ----------------eth---------------------
10 destination eth addr: 00:90:0b:12:58:2b
11 source eth addr: 08:00:27:25:e7:52
12 protocol is: 0800
13 ----------------ip----------------------
14 version: 4
15 head len: 20
16 total len: 184
17 ttl: 64
18 protocol: 6
19 check: f793
20 saddr: 192.168.16.125
21 daddr: 119.84.70.22
22 ----------------tcp---------------------
23 tcp len: 20
24 tcp->doff: 20
25 source port: 55420
26 dest port: 80
27 sequence number: 12053
28 ack sequence: 5286
29 ----------------HTTP---------------------
30 url_len: 54
31 url: http://cc.stream.qqmusic.qq.com/C200003a0iyj2fOc6y.m4a

用 libpcap抓取http报文相关推荐

  1. 使用 nlmon 驱动抓取 netlink 报文的原理

    前言 在 如何抓取 netlink 报文 这篇博客中,我描述了使用 nlmon 驱动创建虚拟 tap 口抓取 netlink 报文的过程,在这篇文章中,我探讨下这一过程背后的原理. nlmon 驱动 ...

  2. tcpdump抓取ipip报文

    根据目的ip抓取ipip单向报文 tcpdump -i p6p1 "ip proto 4 and (ip[20+16:1]=10 and ip[20+17:1]=184 and ip[20+ ...

  3. libpcap抓取数据包

    libpcap是数据包捕获函数库.该库提供的C函数接口可用于需要捕获经过网络接口数据包的系统开发上.libpcap提供的接口函数主要实现和封装了与数据包截获有关的过程.这个库为不同的平台提供了一致的编 ...

  4. tcpdump抓取udp报文

    使用tcpdump命令抓取UDP 2000端口报文,并将报文保存到当前目录下的udp.cap文件,命令如下: tcpdump -i 网络接口名称 udp port 2000 -w ./udp.cap ...

  5. Fiddler实现IOS手机抓取https报文

    如何设置代理访问内网进而抓取手机的Https报文进行分析定位. 准备工作: 1.PC上连接好VPN 2.管理员方式打开Fiddler工具 开搞: 一.设置Fiddler 1.打开Tools->O ...

  6. python scapy抓取http报文内容

    一.使用scapy,简单的用来抓取http相关报文 #coding=utf-8import scapy.all as scapy from scapy.layers.http import HTTPR ...

  7. wireshark中抓取ICMP报文

    为了更有效地转发IP数据报和提高交付成功的机会,在网络层使用了网际控制报文协议ICMP(Internet Control Message Protocol)[RFC 792].它是TCP/IP协议族的 ...

  8. linux抓取tcp报文头部,3.2.3 使用tcpdump观察TCP头部信息

    3.2.3 使用tcpdump观察TCP头部信息 在2.3节中,我们利用tcpdump抓取了一个数据包并分析了其中的IP头部信息,本节分析其中与TCP协议相关的部分(后面的分析中,我们将所有tcpdu ...

  9. wireshark抓取常用报文协议过滤法则大全

    做应用识别这一块经常要对应用产生的数据流量进行分析. 抓包采用wireshark,提取特征时,要对session进行过滤,找到关键的stream,这里总结了wireshark过滤的基本语法,供自己以后 ...

最新文章

  1. Day 24: 使用Yeoman自动构建Ember项目
  2. mysql root 权限注入_Mysql注入root权限直接写一句话马
  3. linux之循环执行任务
  4. wine最小化游戏后无法恢复的问题
  5. [小技巧][JAVA][转换]字符数组char[]与字符串String之间互相转换
  6. cannot resolve symbol xxxx问题
  7. Nginx服务安全加固
  8. 微软 python替代vba_微软将要用Python取代VBA,Python工程师又双叒叕要涨薪了!
  9. 天天工作拧螺丝,怎么突破瓶颈?
  10. 【晒出你的第83行代码】跬步千里,十二年的老代码更是技术的沉淀!
  11. 西门子V90 PN伺服EPOS模式+FB284功能库使用示例教程(图文)
  12. 空间参考(一)---墨卡托投影、高斯-克吕格投影、UTM投影的异同
  13. 软件:10款免费无广告的看图软件,总有一款适合你
  14. PID调节之积分(I)调节
  15. 第三篇:【重磅】呼叫中心运营指标KPI字典
  16. Unity学习 — 官方中文版本教程详解
  17. Java 获取指定日期
  18. 李阳疯狂英语-228句口语要素
  19. phone4s怎么越狱?iphone4s越狱教程图文解...
  20. 初学List和Set集合

热门文章

  1. 利用gcc自带的功能-fstack-protector检测栈溢出及其实现
  2. 3 CSS 高级语法
  3. python加载dll函数失败_Python:使用ctypes访问DLL函数 – 按函数* name *访问失败
  4. 局部钩子能防全局钩子吗_Django局部钩子和全局钩子
  5. 南京信息工程大学c语言真题,南京信息工程大学C语言试题库.doc
  6. pyqt 子窗口控制主窗口绘图_实战PyQt5: 005-主窗口QMainWindow
  7. c语言文件加密异或操作,用异或算法实现文件的简单加密
  8. Halcon - 测量 - 轮廓到线的距离
  9. 浅谈 温故知新——HTML5!
  10. 蓝桥杯历届试题 国王的烦恼(并查集逆序加边+坑)