在 Linux 中,可以使用套接字(socket)和 libpcap 库来实现类似 tcpdump 的功能。libpcap 库提供了捕获网络数据包的接口,而使用套接字则可以将捕获到的数据包发送到指定目的地。
下面是一个简单的使用 C++ 和 libpcap 库实现 tcpdump 功能的示例代码:
#include <iostream>
#include <pcap.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
void packet_callback(u_char *user, const struct pcap_pkthdr *header, const u_char *packet)
{
// 获取 IP 报文头
const struct iphdr* ip_header = (struct iphdr*)(packet + sizeof(struct ethhdr));
// 判断是否为 TCP 报文
if (ip_header->protocol == IPPROTO_TCP)
{
// 获取 TCP 报文头
const struct tcphdr* tcp_header = (struct tcphdr*)(packet + sizeof(struct ethhdr) + sizeof(struct iphdr));
// 打印源地址、目标地址和目标端口
std::cout << "Source: " << inet_ntoa(*(in_addr*)&ip_header->saddr);
std::cout << " Destination: " << inet_ntoa(*(in_addr*)&ip_header->daddr);
std::cout << " Port: " << ntohs(tcp_header->dest) << std::endl;
}
}
int main(int argc, char* argv[])
{
char errbuf[PCAP_ERRBUF_SIZE];
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <interface>" << std::endl;
return 1;
}
pcap_t* handle = pcap_open_live(argv[1], BUFSIZ, 1, 1000, errbuf);
if (handle == nullptr)
{
std::cerr << "pcap_open_live() failed: " << errbuf << std::endl;
return 1;
}
// 过滤 TCP 报文
struct bpf_program tcp_filter;
if (pcap_compile(handle, &tcp_filter, "tcp", 0, 0) == -1)
{
std::cerr << "pcap_compile failed: " << pcap_geterr(handle) << std::endl;
return 1;
}
if (pcap_setfilter(handle, &tcp_filter) == -1)
{
std::cerr << "pcap_setfilter failed: " << pcap_geterr(handle) << std::endl;
return 1;
}
// 捕获网络数据包并输出
pcap_loop(handle, -1, packet_callback, nullptr);
pcap_close(handle);
return 0;
}
在上面的代码中,我们使用了 libpcap 库提供的 pcap_open_live
函数打开指定网卡的捕获接口,并使用 pcap_loop
函数循环捕获网络数据包。每当有数据包到达时,回调函数 packet_callback
将被调用,可以在该回调函数中对数据包进行处理。
在 packet_callback
函数中,我们首先通过偏移量获取 IP 报文头和 TCP 报文头,然后判断是否为 TCP 报文。如果是,我们将打印源地址、目标地址和目标端口等信息。
在程序中,我们使用了 pcap_compile
和 pcap_setfilter
函数来设置过滤器,只捕获 TCP 报文。这样可以避免无用的数据包干扰分析结果。