Linux下使用C语言实现网络数据包捕获 libpcap教程 (linux c libpcap)
Introduction
在计算机网络中,数据包是网络通信的基本单位,可以帮助我们了解如何评估网络性能及0某个应用程序活动的细节。为了监视传入和传出网络流量,并对其进行统计和分析,可以使用一种叫做“数据包捕获”的技术,该技术可以在网络中捕获和分析网络数据包。本文将介绍如何在Linux系统下使用C语言编写程序实现网络数据包捕获,同时我们将使用一款名为libpcap的网络抓包库。
Installing libpcap
我们需要安装libpcap库,该库是用于捕获、分析和重放网络数据包的库。在Ubuntu和Debian系统中,可以通过下面的命令来安装libpcap:
sudo apt-get install libpcap-dev
在Fedora系统中,可以通过下面的命令来安装:
sudo yum install libpcap-devel
在其他类似Red Hat的发行版系统中,可以使用以下命令:
sudo dnf install libpcap-devel
Writing the Program
有了libpcap库后,我们需要编写一个程序来使用该库进行数据包捕获。我们的程序将:
使用pcap_lookupdev函数来查找网络接口名称。
使用pcap_create函数打开网络接口以进行数据包捕获。在此函数中,以及将该接口设置为非阻塞模式。
使用pcap_loop函数来无限循环捕获数据包,当有数据包到达时就会调用处理函数(在本文中为process_packet)。
以下是程序的完整源代码:
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#endif
#include
#include
void process_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
int mn(int argc, char *argv[]) {
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = “ip”;
bpf_u_int32 net;
bpf_u_int32 mask;
if (pcap_lookupnet(argv[1], &net, &mask, errbuf) == -1) {
fprintf(stderr, “Couldn’t get netmask for device %s: %s\n”, argv[1], errbuf);
net = 0;
mask = 0;
}
handle = pcap_create(argv[1], errbuf);
if (handle == NULL) {
fprintf(stderr, “Couldn’t open device %s: %s\n”, argv[1], errbuf);
return(2);
}
if (pcap_set_snaplen(handle, 65535) != 0) {
fprintf(stderr, “Couldn’t set snaplen: %s\n”, pcap_geterr(handle));
return(3);
}
if (pcap_set_promisc(handle, 1) != 0) {
fprintf(stderr, “Couldn’t set promiscuous mode: %s\n”, pcap_geterr(handle));
return(4);
}
if (pcap_set_timeout(handle, 1000) != 0) {
fprintf(stderr, “Couldn’t set timeout: %s\n”, pcap_geterr(handle));
return(5);
}
if (pcap_activate(handle) != 0) {
fprintf(stderr, “Couldn’t activate capture: %s\n”, pcap_geterr(handle));
return(6);
}
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(7);
}
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, “Couldn’t install filter %s: %s\n”, filter_exp, pcap_geterr(handle));
return(8);
}
pcap_loop(handle, -1, process_packet, NULL);
pcap_close(handle);
}
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
struct sockaddr_in source, dest;
int protocol;
char source_ip[INET_ADDRSTRLEN], dest_ip[INET_ADDRSTRLEN];
u_int source_port, dest_port;
struct iphdr *iph = (struct iphdr *)(packet + ETHER_HDR_LEN);
if (iph->protocol == IPPROTO_TCP) {
struct tcphdr *tcph = (struct tcphdr *)(packet + ETHER_HDR_LEN + (iph->ihl * 4));
source.sin_addr.s_addr = iph->saddr;
dest.sin_addr.s_addr = iph->daddr;
source_port = ntohs(tcph->source);
dest_port = ntohs(tcph->dest);
protocol = IPPROTO_TCP;
} else if (iph->protocol == IPPROTO_UDP) {
struct udphdr *udph = (struct udphdr *)(packet + ETHER_HDR_LEN + (iph->ihl * 4));
source.sin_addr.s_addr = iph->saddr;
dest.sin_addr.s_addr = iph->daddr;
source_port = ntohs(udph->source);
dest_port = ntohs(udph->dest);
protocol = IPPROTO_UDP;
} else if (iph->protocol == IPPROTO_ICMP) {
struct icmphdr *icmph = (struct icmphdr *)(packet + ETHER_HDR_LEN + (iph->ihl * 4));
source.sin_addr.s_addr = iph->saddr;
dest.sin_addr.s_addr = iph->daddr;
source_port = 0;
dest_port = 0;
protocol = IPPROTO_ICMP;
} else {
source.sin_addr.s_addr = iph->saddr;
dest.sin_addr.s_addr = iph->daddr;
source_port = 0;
dest_port = 0;
protocol = iph->protocol;
}
inet_ntop(AF_INET, &(source.sin_addr), source_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(dest.sin_addr), dest_ip, INET_ADDRSTRLEN);
printf(“Source: %s:%d Dest: %s:%d Protocol: %d\n”, source_ip, source_port, dest_ip, dest_port, protocol);
}
Conclusion