• 使用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
  • 相关阅读:
    aspose.word 页脚插入图片图片浮动
    Aspose.Words插入表格,表格居中显示
    git常用命令
    openlayers之矢量加载标记点
    三、反射、动态加载
    openlayers交互之多边形
    openlayers轨迹回放
    openlayers交互之线
    关闭2000的默认共享
    开始blog,有点晚,但还是早
  • 原文地址:https://www.cnblogs.com/wenqiang/p/5773336.html
Copyright © 2020-2023  润新知