zoukankan      html  css  js  c++  java
  • 使用libpcap获取http报文

    在上一篇博客中简单对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---------------------
    ");
     27     printf("destination eth addr: %02x:%02x:%02x:%02x:%02x:%02x
    ",
     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
    ",
     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
    ", 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----------------------
    ");
     44     printf("version: %d
    ", ip->version);
     45     printf("head len: %d
    ", ip->ihl * 4);
     46     printf("total len: %d
    ", ntohs(ip->tot_len));
     47     printf("ttl: %d
    ", ip->ttl);
     48     printf("protocol: %d
    ", ip->protocol);
     49     printf("check: %x
    ", ip->check);
     50     addr.s_addr = ip->saddr;
     51     printf("saddr: %s
    ", inet_ntoa(addr));
     52     addr.s_addr = ip->daddr;
     53     printf("daddr: %s
    ", inet_ntoa(addr));
     54 }
     55 
     56 /*Display TCP Header*/
     57 void show_tcphdr(struct tcphdr *tcp)
     58 {
     59     printf("----------------tcp---------------------
    ");
     60     printf("tcp len: %d
    ", sizeof(struct tcphdr));
     61     printf("tcp->doff: %d
    ", tcp->doff * 4);
     62     printf("source port: %d
    ", ntohs(tcp->source));
     63     printf("dest port: %d
    ", ntohs(tcp->dest));
     64     printf("sequence number: %d
    ", ntohs(tcp->seq));
     65     printf("ack sequence: %d
    ", 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---------------------
    ");
    126     printf("url_len: %d
    ", url_len);
    127     printf("url: %s
    ", 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("
    ----------------------------------------
    ");
    180     printf("		packet %d
    ", count);
    181     printf("----------------------------------------
    ");
    182     printf("Packet id: %d
    ", count);
    183     printf("Packet length: %d
    ", pkthdr->len);  
    184     printf("Number of bytes: %d
    ", pkthdr->caplen);  
    185       printf("Recieved time: %s
    ", 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
    ");
    204         exit(1);
    205     }
    206     addr.s_addr = netp;
    207     net = inet_ntoa(addr);
    208     printf("network: %s
    ", net);
    209     
    210     addr.s_addr = maskp;
    211     mask = inet_ntoa(addr);
    212     printf("mask: %s
    ", 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
    ", 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
  • 相关阅读:
    some tips
    ORA00847: MEMORY_TARGET/MEMORY_MAX_TARGET and LOCK_SGA cannot be set together
    Chapter 01Overview of Oracle 9i Database Perfomrmance Tuning
    Chapter 02Diagnostic and Tuning Tools
    变量与常用符号
    Chapter 18Tuning the Operating System
    标准输入输出
    Trace files
    DBADeveloped Tools
    Chapter 03Database Configuration and IO Issues
  • 原文地址:https://www.cnblogs.com/wenqiang/p/5773336.html
Copyright © 2011-2022 走看看