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 *) ðernet_hdr->ether_shost));
fprintf(stdout, "\tDst: %s\n", ether_ntoa((const struct ether_addr *) ðernet_hdr->ether_dhost));
}
else if (verbosity == MEDIUM) {
fprintf(stdout, "ETHERNET, ");
fprintf(stdout, "Src: %s, ", ether_ntoa((const struct ether_addr *) ðernet_hdr->ether_shost));
fprintf(stdout, "Dst: %s\n", ether_ntoa((const struct ether_addr *) ðernet_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