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


数据运维技术 » Linux下使用C语言实现网络数据包捕获 libpcap教程 (linux c libpcap)