一、
在 C 语言中实现 TCP 抓包功能,通常可以使用 libpcap 库。libpcap 是一个广泛使用的网络抓包库,它提供了捕获网络数据包的接口。
libpcap 是一个广泛使用的 C 语言库,用于捕获和过滤网络数据包。它提供了一个通用接口,用于访问数据链路层的协议,使用户能够在各种平台上实现网络流量捕获功能。
二、准备
安装 libpcap:在 Linux 系统中,可以使用以下命令安装
sudo apt-get install libpcap-dev
或者
下载、编译源码
git clone https://github.com/the-tcpdump-group/libpcap
可以查看官方文档
https://www.tcpdump.org/
三、代码
#include <stdio.h>
#include <stdlib.h>
#include <pcap/pcap.h>//头文件包含#define SNAP_LEN 65535
#define PROMISC 1
#define TIMEOUT 1000 // ms
#define BUFSIZE 4 * 1024 * 1024 // 4MBtypedef struct {pcap_dumper_t *dumper; // 用于保存数据包的句柄time_t start_time; // 记录当前文件的起始时间long written_bytes; // 当前文件已写入的字节数int file_index; // 文件索引,用于防止同一秒生成两个文件
} capture_context_t;//抓到包后具体的处理,根据带入的参数和自己需要的规则进行编写功能
void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) {capture_context_t *ctx = (capture_context_t *)user;time_t now = time(NULL);long packet_size = h->caplen;// 更新写入字节数ctx->written_bytes += packet_size;// 计算是否需要切换文件if (difftime(now, ctx->start_time) >= MAX_DURATION_SEC ||ctx->written_bytes >= MAX_FILE_SIZE) {// 关闭旧文件pcap_dump_close(ctx->dumper);// 打开新文件char filename[256];ctx->file_index += 1;generate_filename(filename, sizeof(filename), ctx->file_index);ctx->dumper = pcap_dump_open(ctx->handle, filename);ctx->start_time = now;ctx->written_bytes = 0;printf("🆕 Switched to new file: %s\n", filename);}// 写入当前包pcap_dump((u_char *)ctx->dumper, h, bytes);
}int main() {char errbuf[PCAP_ERRBUF_SIZE];//存放错误打印pcap_t *handle;pcap_dumper_t *dumper;struct bpf_program fp;bpf_u_int32 net = 0, mask = 0;//查找当前系统中一个默认的抓包网络设备名,需要确认是否有权限const char *dev = pcap_lookupdev(errbuf);if (!dev) {fprintf(stderr, "Device not found: %s\n", errbuf);return 1;}const char *filter_exp = "tcp port 80"; // 设置过滤器的规则,可以换成 "udp", "ip", "host 192.168.1.1", 等等const char *outfile = "output.pcap"; // 输出文件printf("Using device: %s\n", dev);// 获取网络地址 & 掩码(用于过滤器编译)if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {fprintf(stderr, " Could not get netmask for %s: %s\n", dev, errbuf);net = 0;mask = 0;}//创建并配置抓包句柄handle = pcap_create(dev, errbuf);if (!handle) {fprintf(stderr, " pcap_create failed: %s\n", errbuf);return 1;}//设置抓包长度pcap_set_snaplen(handle, SNAP_LEN);//混杂模式,当网络接口处于混杂模式时,它会接收所有经过的数据包,而不仅仅是发送给它的包。pcap_set_promisc(handle, PROMISC);//设置捕获数据包的超时时间,以毫秒为单位,表示在没有接收到数据包的情况下,等待的最长时间pcap_set_timeout(handle, TIMEOUT);//设置缓冲区大小,增大缓冲区可以提高捕获性能,尤其是在高流量环境中,可以防止数据包丢失。pcap_set_buffer_size(handle, BUFSIZE);//激活刚刚设置的参数if (pcap_activate(handle) != 0) {fprintf(stderr, " pcap_activate failed: %s\n", pcap_geterr(handle));return 1;}//编译 BPF(Berkeley Packet Filter)过滤器表达式,将过滤规则转化为库格式if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {fprintf(stderr, " Couldn't parse filter: %s\n", pcap_geterr(handle));return 1;}//应用过滤规则if (pcap_setfilter(handle, &fp) == -1) {fprintf(stderr, " Couldn't install filter: %s\n", pcap_geterr(handle));return 1;}// 打开输出文件dumper = pcap_dump_open(handle, outfile);if (!dumper) {fprintf(stderr, " Couldn't open dump file: %s\n", pcap_geterr(handle));return 1;}capture_context_t ctx = { .dumper = dumper };printf(" Saving packets to: %s\n", outfile);//抓多少包,抓到的包怎么处理packet_handlerpcap_loop(handle, 10, packet_handler, (u_char *)&ctx); // 抓 10 个包// 清理资源pcap_dump_close(dumper);pcap_freecode(&fp);pcap_close(handle);printf(" Capture complete. Output saved to: %s\n", outfile);return 0;
}
编译、需要进行库的链接,以及操作权限
gcc -o pcap_loop_example pcap_loop_example.c -lpcap
sudo ./pcap_loop_example
#四、Shell 脚本(自动添加权限)
可以当做自启动脚本
#!/bin/bash
# file: grant_pcap_cap.shTARGET="./pcap_loop_example "if [ ! -f "$TARGET" ]; thenecho "❌ $TARGET not found. Please compile it first."exit 1
fiecho "🔧 Adding capability to $TARGET ..."
sudo setcap cap_net_raw,cap_net_admin=eip $TARGETecho "✅ Done. You can now run it as a normal user:"
echo " $TARGET"