Linux网络编程六、报文解析(1)

一、pcap文件解析

  依赖的库:libpcap,头文件:pcap/pcap.h

  获取pcap文件:tcpdump,-i:指定监听接口,默认配置好的最小的号码的接口。-w:指定存入文件,将原始报文存入指定文件。-r:读取指定文件。

  解析pcap文件:

    1、pcap_t *pcap_open_offline(char *fname, char *ebuf);

      打开指定的pcap文件。

      fname:文件名。

      ebuf:传出参数,传出pcap_open_offline出错返回NULL时的错误消息。

      返回值:成功返回对应文件的指针,失败返回NULL。

    2、int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user);

      处理pcap数据。

      p:指定处理目标。

      cnt:指定处理数量。-1或0则为无限大,p指定的是保存下来的文件,则处理到文件尾,p指定的是实时数据,则一直处理下去,直到出错或者调用pcap_breakloop()。

      callback:指定处理数据的回调函数。typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);  user为pcap_loop第三个参数user,h结构体指针,存储数据报的时间戳和长度,caplen为抓取到报文实际大小,len为理论大小,两者大小不一致说明报文弄断不能解析。bytes为数据报的首地址。

      user:回调函数的传入传出参数。

      返回值:数据处理完返回0,出错返回PCAP_ERROR,循环结束或调用pcap_breakloop()返回PCAP_ERROR_BREAK,处理实时数据不返回。

    3、int pcap_dispatch();  参数列表和功能同pcap_loop(),不同之处在于处理实时数据时超时loop不返回,阻塞,而pcap_dispatch会返回。返回处理的数据数量。

    4、void pcap_breakloop(pcap_t *);  终止loop或dispatch函数。

    5、void pcap_close(pcap_t *p);  关闭并释放打开的pcap_t。

    6、pcap_t *pcap_create(const char *source, char *errbuf);

      创建监听实时数据的pcap_t。source指定监听接口,指定为"any"或者NULL则监听所有接口。errbuf同上。pcap_open_live()功能同create,live参数配置复杂,但是可以指定超时时间。

二、以太网帧解析

  头文件:/usr/include/net/ethernet.h

//ethernet.h代码片段
struct ether_header
{
    uint8_t ether_dhost[ETH_ALEN];    //目标MAC地址,ETH_ALEN一般为6
    uint8_t ether_shost[ETH_ALEN];   //源....
    uint6_t ether_type;    //包裹的数据类型:IP,ARP,RARP。判断时用htons(nums)将nums转成网络字节顺序
}

 例:

#include <pcap/pcap.h>
#include <net/ethernet.h>
#include <stdio.h>
#include <arpa/net.h>

char errbuf[PCAP_ERRBUF_SIZE]={0};
pcap_t *handle=NULL;
handle=pcap_open_offline("a.cap", errbuf);
pcap_loop(handle, -1, handler, NULL);

//回调函数
void handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
    struct ether_header* ether_packet= (struct ether_header*)bytes;
    int ether_len=h->caplen;
    printf("ether_len= %d\n", ether_len);
    printf("dmac: ");
    for(int i= 0; i<6; ++i)
    {
        printf("%02x", ether_packet->ether_dhost[i]);
    }
    printf("\n");

    printf("smac: ");
    for(int i= 0; i<6; ++i)
    {
        printf("%02x", ether_packet->ether_shost[i]);
    }
    printf("\n");

    if (ether_packet->ether_type == htons(0x0800)) //判断是否是IP
    {
        //IP
        // .......
    }
    
}

 

posted @ 2019-11-26 22:48  qetuo[  阅读(1093)  评论(0编辑  收藏  举报