一、
在 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"