数据包捕获与分析

本文介绍数据包的捕获与按照协议格式进行数据包分析。数据包捕获采用了libpcap抓包框架,能够分析IP、TCP、UDP、ARP、RARP等类型的数据包。


一、数据包捕获

数据包的捕获采用了libpcap函数库,下面介绍捕获过程中各函数的使用步骤。


1. 获取网络接口

char *pcap_lookupdev(char *errbuf)

用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络设备名指针。如果函数出错,则返回NULL,同时errbuf中存放相关的错误消息。


2. 打开网络接口

pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)

上面这个函数会返回指定接口的pcap_t类型指针,后面的所有操作都要使用这个指针。
第一个参数是第一步获取的网络接口字符串,可以直接使用硬编码。
第二个参数是对于每个数据包,从开头要抓多少个字节。
第三个参数指定是否打开混杂模式(Promiscuous Mode),0表示非混杂模式,任何其他值表示混合模式。如果要打开混杂模式,那么网卡必须也要打开混杂模式。
第四个参数指定需要等待的毫秒数,0表示一直等待直到有数据包到来。
第五个参数是存放出错信息的数组。


3. 设置过滤器

虽然不设置过滤器本实验也能分析各种协议的数据包,但是设置过滤器能获取特定的包,增强实验的目的性。实现这一过程由pcap_compile()与pcap_setfilter()这两个函数完成。
int pcap_compile(pcap_t *p, strUCt bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

第一个参数是会话句柄。接下来的是我们存储被编译的过滤器版本的地址的引用。再接下来的则是表达式本身,存储在规定的字符串格式里。再下边是一个定义表达式是否被优化的整形量(0为false,1为true,标准规定)。最后,我们必须指定应用此过滤器的网络掩码。函数返回-1为失败,其他的任何值都表明是成功的。表达式被编译之后就可以使用了。

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

第一个参数是会话句柄,第二个参数是被编译表达式版本的引用。


4. 获取数据包

Libpcap中获取数据包最常用的函数是int pcap_loop()。
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
此函数提供了抓包工具的核心功能。第一个参数是第2步返回的pcap_t类型的指针。第二个参数是需要抓的数据包的个数,一旦抓到了cnt个数据包,pcap_loop立即返回。负数的cnt表示pcap_loop永远循环抓包,直到出现错误。第三个参数是一个回调函数指针,它必须是如下的形式:
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
其中:第一个参数是pcap_loop的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它。第二个参数是收到的数据包的pcap_pkthdr类型的指针。第三个参数是收到的数据包数据。
后面,我们将调用回调函数callback() 来进行数据包的分析,回调函数提供了数据包分析的核心功能。


二、数据包分析

1. 数据包分析原理

在libpcap定义的回调函数中,有一个参数const u_char *packet,它是一个u_char类型的指针,包含了所有被pcap_loop()所嗅探到的包。每一个包其实是一块连续的内存,packet指针指向这块内存的起始位置。一个数据包包含许多属性,因此可以看做一个包含许多成员变量的结构体。事先按照协议的格式定义好结构体,然后用这块内存装载,则结构体的成员变量将会与数据包信息一一对应。这样,就拿到了数据包的信息。
下面是一些数据包的结构体定义。各协议头部可以自己定义,也可以查看Linux  /usr/include/netinet 下的各种协议头部的结构体定义。
/* IP header*/
struct 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)
};

/* ARP Header*/ 
struct arp { 
    u_int16_t htype;    /* Hardware Type           */ 
    u_int16_t ptype;    /* Protocol Type           */ 
    u_char hlen;        /* Hardware Address Length */ 
    u_char plen;        /* Protocol Address Length */ 
    u_int16_t oper;     /* Operation Code          */ 
    u_char sha[6];      /* Sender hardware address */ 
    u_char spa[4];      /* Sender IP address       */ 
    u_char tha[6];      /* Target hardware address */ 
    u_char tpa[4];      /* Target IP address       */ 
	#define ARP_REQUEST 1
	#define ARP_REPLY 2
}; 

/* TCP header */
typedef u_int tcp_seq;

struct 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 */
};




猜你喜欢

转载自blog.csdn.net/u012327058/article/details/73480732