Menu

PCAP 协议分析 初始化和链路层

作为自由职业者已经有一段时间了,除了自己的项目以外,就是一些客户的项目。最近的接的活主要的工作是协议分析。客户从光设备上,收集网络数据,然后交由我的系统进行协议分析。

首先,我们确定了以pcap格式作为数据信息格式,而我也找到了一些参考。经过一些测试,我决定采用tcpdump的libpcap作为pcap格式库,从而一步一步的进行分析协议。

先不关心上层协议,先来实用libpcap搭建最基础的链路层协议读取。(libpcap : https://www.tcpdump.org/ )

libpcap可以自己抓包,类似于wireshark工具。不过,我是采用wireshark抓包后,保存成pcap格式,然后进行分析。其实过程都一样,只是我这样做比较符合目前的应用场景。

初始化libpcap的参考代码:

char errbuf[PCAP_ERRBUF_SIZE];

/**
 * @brief this function is the callback function for pcap_loop. Launch the analysis of the packet
 * @param args
 * @param header
 * @param packet
 */
void handle_packet(u_char* args, const struct pcap_pkthdr* header, const u_char* packet){
    static int nbPacket = 1;
    fprintf(stdout, "\n--- [PACKET #%d - %d bytes] ----------------------------------------------- \n", nbPacket, header->len);
    handle_ethernet(packet, verbosity);
    fprintf(stdout, "\n");
    nbPacket++;
}

pcap_t* capture_offine(char* file) {
    pcap_t* interface;
    if((interface = pcap_open_offline(file, errbuf)) == NULL) {
        fprintf(stderr, "Unable to open %s\n", file);
        exit(EXIT_FAILURE);
    }

    return interface;
}

pcap_t* interface = NULL;

interface = capture_offine(optarg);

//run treatment loop
    int ret;
    ret = pcap_loop(interface, -1, handle_packet, NULL);

    if (ret != 0)
        fprintf(stdout, "Error pcap_loop\n");

    //exit proprely
    if (filter_selected != 0)
        pcap_freecode(&fp);

    pcap_close(interface);

 

经过上述代码,解析出的每一个packet都将会被回调。然后,就开始分析第一层,链路层的数据,核心代码:

void handle_ethernet(const u_char* packet, int verbosity){
    struct ether_header* ethernet_hdr;
    int ethernet_size = sizeof(struct ether_header);
    ethernet_hdr = (struct ether_header*) packet;
    int type = ntohs ((uint16_t) ethernet_hdr->ether_type);

    if (verbosity == HIGH){
        fprintf(stdout, "ETHERNET\n");
        fprintf(stdout, "\tSrc: %s\n", ether_ntoa((const struct ether_addr *) &ethernet_hdr->ether_shost));
        fprintf(stdout, "\tDst: %s\n", ether_ntoa((const struct ether_addr *) &ethernet_hdr->ether_dhost));
    }
    else if (verbosity == MEDIUM) {
        fprintf(stdout, "ETHERNET, ");
        fprintf(stdout, "Src: %s, ", ether_ntoa((const struct ether_addr *) &ethernet_hdr->ether_shost));
        fprintf(stdout, "Dst: %s\n", ether_ntoa((const struct ether_addr *) &ethernet_hdr->ether_dhost));
    }

    //shift
    packet += ethernet_size;

    switch (type) {
        case ETHERTYPE_IP:
            handle_ip(packet, verbosity);
        break;

        case ETHERTYPE_ARP:
            handle_arp(packet, verbosity);
        break;

        case ETHERTYPE_IPV6:    //ipv6 is not supported
            if (verbosity == HIGH)
                fprintf(stdout, "\t");
            fprintf(stdout, "IPv6 (Unsuppported)");
        break;

        default:
            break;
    }

}

下一次,我们讲网络层和传输层。

Categories:   Garfield's Diary

Comments