用 libpcap抓取http报文

来源:互联网 发布:php 过滤数组中的空值 编辑:程序博客网 时间:2024/05/17 22:45

在上一篇博客中简单对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:2b11 source eth addr: 08:00:27:25:e7:5212 protocol is: 080013 ----------------ip----------------------14 version: 415 head len: 2016 total len: 18417 ttl: 6418 protocol: 619 check: f79320 saddr: 192.168.16.12521 daddr: 119.84.70.2222 ----------------tcp---------------------23 tcp len: 2024 tcp->doff: 2025 source port: 5542026 dest port: 8027 sequence number: 1205328 ack sequence: 528629 ----------------HTTP---------------------30 url_len: 5431 url: http://cc.stream.qqmusic.qq.com/C200003a0iyj2fOc6y.m4a