libpcap 库使用(一)

参考资料:

  http://www.tcpdump.org/

DESCRIPTION

The Packet Capture library provides a high level interface to packet capture systems. All packets on the network, even those destined for other hosts, are accessible through this mechanism. It also supports saving captured packets to a ``savefile'', and reading packets from a ``savefile''.

 

Getting Started: The format of a pcap application

The first thing to understand is the general layout of a pcap sniffer. The flow of code is as follows:

  1. We begin by determining which interface we want to sniff on. In Linux this may be something like eth0, in BSD it may be xl1, etc. We can either define this device in a string, or we can ask pcap to provide us with the name of an interface that will do the job.
  2. Initialize pcap. This is where we actually tell pcap what device we are sniffing on. We can, if we want to, sniff on multiple devices(如何同时探测多个设备?). How do we differentiate between them? Using file handles. Just like opening a file for reading or writing, we must name our sniffing "session" so we can tell it apart from other such sessions.
  3. In the event that we only want to sniff specific traffic (e.g.: only TCP/IP packets, only packets going to port 23, etc) we must create a rule set, "compile" it, and apply it. This is a three phase process, all of which is closely related. The rule set is kept in a string, and is converted into a format that pcap can read (hence compiling it.) The compilation is actually just done by calling a function within our program; it does not involve the use of an external application. Then we tell pcap to apply it to whichever session we wish for it to filter.
  4. Finally, we tell pcap to enter it's primary execution loop. In this state, pcap waits until it has received however many packets we want it to. Every time it gets a new packet in, it calls another function that we have already defined. The function that it calls can do anything we want; it can dissect the packet and print it to the user, it can save it in a file, or it can do nothing at all.
  5. After our sniffing needs are satisfied, we close our session and are complete.

This is actually a very simple process. Five steps total, one of which is optional (step 3, in case you were wondering.) Let's take a look at each of the steps and how to implement them.

翻译:

  1.确定要探测的dev;

    #include <stdio.h>
    #include <pcap.h>

    int main(int argc, char *argv[])
    {
         char *dev = argv[1];

         printf("Device: %s\n", dev);
         return(0);
    }

   //或者

    #include <stdio.h>
    #include <pcap.h>

    int main(int argc, char *argv[])
    {
        char *dev, errbuf[PCAP_ERRBUF_SIZE];

        dev = pcap_lookupdev(errbuf);  //随便找一个默认的interface
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        printf("Device: %s\n", dev);
        return(0);
    }

 

  2.初始化pcap;

     #include <pcap.h>
     ...
     pcap_t *handle;

     handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
     if (handle == NULL) {
         fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
         return(2);
     }

 

  3.想要探测特定类型的报文,设置rule;

     #include <pcap.h>
     #include <stdio.h>

     int main(int argc, char *argv[])
     {
        pcap_t *handle;            /* Session handle */
        char *dev;            /* The device to sniff on */
        char errbuf[PCAP_ERRBUF_SIZE];    /* Error string */
        struct bpf_program fp;        /* The compiled filter */
        char filter_exp[] = "port 23";    /* The filter expression */
        bpf_u_int32 mask;        /* Our netmask */
        bpf_u_int32 net;        /* Our IP */
        struct pcap_pkthdr header;    /* The header that pcap gives us */
        const u_char *packet;        /* The actual packet */

        /* Define the device */
        dev = pcap_lookupdev(errbuf);
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        /* Find the properties for the device */
        if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
            fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
            net = 0;
            mask = 0;
        }
        /* Open the session in promiscuous mode */
        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
        if (handle == NULL) {
            fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
            return(2);
        }
        /* Compile and apply the filter */
        if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
            fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
            return(2);
        }
        if (pcap_setfilter(handle, &fp) == -1) {
            fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
            return(2);
        }
        /* Grab a packet */
        packet = pcap_next(handle, &header);
        /* Print its length */
        printf("Jacked a packet with length of [%d]\n", header.len);
        /* And close the session */
        pcap_close(handle);
        return(0);
     }

 

  4.报文接收;

//抓取单个报文
u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

//抓取多个报文
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);  //回调函数

 

 

  报文解析:

/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN    6

    /* Ethernet header */
    struct sniff_ethernet {
        u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
        u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
        u_short ether_type; /* IP? ARP? RARP? etc */
    };

    /* IP header */
    struct sniff_ip {
        u_char ip_vhl;        /* version << 4 | header length >> 2 */
        u_char ip_tos;        /* type of service */
        u_short ip_len;        /* total length */
        u_short ip_id;        /* identification */
        u_short ip_off;        /* fragment offset field */
    #define IP_RF 0x8000        /* reserved fragment flag */
    #define IP_DF 0x4000        /* dont fragment flag */
    #define IP_MF 0x2000        /* more fragments flag */
    #define IP_OFFMASK 0x1fff    /* mask for fragmenting bits */
        u_char ip_ttl;        /* time to live */
        u_char ip_p;        /* protocol */
        u_short ip_sum;        /* checksum */
        struct in_addr ip_src,ip_dst; /* source and dest address */
    };
    #define IP_HL(ip)        (((ip)->ip_vhl) & 0x0f)
    #define IP_V(ip)        (((ip)->ip_vhl) >> 4)

    /* TCP header */
    typedef u_int tcp_seq;

    struct sniff_tcp {
        u_short th_sport;    /* source port */
        u_short th_dport;    /* destination port */
        tcp_seq th_seq;        /* sequence number */
        tcp_seq th_ack;        /* acknowledgement number */
        u_char th_offx2;    /* data offset, rsvd */
    #define TH_OFF(th)    (((th)->th_offx2 & 0xf0) >> 4)
        u_char th_flags;
    #define TH_FIN 0x01
    #define TH_SYN 0x02
    #define TH_RST 0x04
    #define TH_PUSH 0x08
    #define TH_ACK 0x10
    #define TH_URG 0x20
    #define TH_ECE 0x40
    #define TH_CWR 0x80
    #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
        u_short th_win;        /* window */
        u_short th_sum;        /* checksum */
        u_short th_urp;        /* urgent pointer */
};

  5.探测结束之后,关闭我们的session。

void pcap_close(pcap_t *p);

 

 

总结:

  上述描述了一个通过libpcap实现抓包的基本框架

 

posted on 2019-04-02 15:13  rivsidn  阅读(3418)  评论(0编辑  收藏  举报

导航