Mac平台下C语言pcap抓包程序无输出问题排查求助
Mac系统下pcap实时抓包程序无输出问题解决
问题描述
使用pcap库开发C语言网络抓包程序,预期捕获实时数据包并输出时间戳、捕获长度、可打印文本数据等信息,但在Mac系统下执行sudo ./[PROGRAM_NAME] [DEVICE_NAME]时终端无任何输出。
程序预期逻辑
- 接收命令行传入的网络接口名称
- 调用
pcap_findalldevs()获取设备列表,校验传入设备是否存在 - 设备存在则调用
pcap_open_live()开启实时抓包会话 - 设置空过滤规则以捕获所有数据包
- 进入
pcap_loop()循环,通过packet_handler()处理数据包
原始代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/ethernet.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include <pcap.h> #define STARTING_INDEX 0 void packet_handler(u_char* args, const struct pcap_pkthdr* header, const u_char* rawdata); int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "argc must be 2 or more (in later versions)\n"); return 1; } char ERRBUF[PCAP_ERRBUF_SIZE]; memset(ERRBUF, 0, sizeof(ERRBUF)); pcap_if_t* devices; if (pcap_findalldevs(&devices, ERRBUF) == -1) { fprintf(stderr, "Failed to look up devices.\n"); return 1; } char device[BUFSIZ]; while (devices->next != NULL) { if (strcmp(argv[1], devices->name) == 0) { strcpy(device, devices->name); break; proc_ retself 半Coffee Vis_ched conducting(-雪�-3) devices = devices->next; } struct bpf_program fp; char filter_exp[] = ""; bpf_u_int32 net; bpf_u_int32 mask; if (pcap_lookupnet(device, &net, &mask, ERRBUF) == -1) { fprintf(stderr, "Failed to get netmask of device.\n"); net = 0; } pcap_t* handle; handle = pcap_open_live(device, BUFSIZ, 1, 1000, ERRBUF); if (handle == NULL) { fprintf(stderr, "Failed to start a sniffing session on device: %s due to error: %s.\n", device, ERRBUF); return 1; } int datalink_type = pcap_datalink(handle); printf("%i\n", datalink_type); if (pcap_compile(handle, &fp, filter_exp, 1, net) == -1) { fprintf(stderr, "Failed to compile filter expression.\n"); return 1; } if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Failed to set up a filter.\n"); return 1; } if (pcap_loop(handle, 0, packet_handler, NULL) == -1) { fprintf(stderr, "Failed to start a packet_capturing session using loop.\n"); return 1; } pcap_close(handle); } void packet_handler(u_char* args, const struct pcap_pkthdr* header, const u_char* rawdata) { fprintf(stdout, "timestamp: %s seconds\n", ctime(&header->ts.tv_sec)); fprintf(stdout, "caplen: %i\n", header->caplen); fprintf(stdout, "len: %i\n", header->len); if (header->caplen == 0) { return; } char* buffer = malloc(sizeof(u_char) * header->caplen); if (buffer == NULL) { fprintf(stderr, "Failed to allocate enough memory.\n"); return 1; } memset(buffer, 0, sizeof(u_char) * header->caplen); int BUFFER_LEN = STARTING_INDEX; for (int i = STARTING_INDEX; i < header->caplen; i++) { if (BUFFER_LEN < header->caplen) if (isprint(rawdata[i])) { buffer[BUFFER_LEN] = (char)(rawdata[i]); BUFFER_LEN++; } } buffer[BUFFER_LEN] = '\0'; fprintf(stdout, "text data: %s\n", buffer); free(buffer); }
问题排查与修复
1. 代码中的乱码语法错误
原始代码存在无效乱码内容:proc_ retself 半Coffee Vis_ched conducting(-雪�-3),直接导致编译失败,需删除并修正设备查找逻辑:
char device[BUFSIZ]; memset(device, 0, sizeof(device)); // 初始化避免未定义行为 pcap_if_t* current_dev = devices; while (current_dev != NULL) { if (strcmp(argv[1], current_dev->name) == 0) { strncpy(device, current_dev->name, sizeof(device)-1); // 防止缓冲区溢出 break; } current_dev = current_dev->next; } // 校验设备是否找到 if (strlen(device) == 0) { fprintf(stderr, "Specified device %s not found.\n", argv[1]); pcap_freealldevs(devices); // 释放资源 return 1; } pcap_freealldevs(devices); // 及时释放设备列表
- 原循环
while (devices->next != NULL)会漏掉最后一个设备,改为遍历所有设备直到current_dev == NULL - 新增设备存在校验,避免后续使用未初始化的
device变量 - 使用
strncpy替代strcpy防止缓冲区溢出
2. packet_handler函数返回值错误
packet_handler是void类型函数,不能返回整数return 1;,需改为return;:
char* buffer = malloc(sizeof(u_char) * header->caplen); if (buffer == NULL) { fprintf(stderr, "Failed to allocate enough memory.\n"); return; // 替换return 1; }
3. 标准输出缓冲问题
Mac系统下stdout默认行缓冲,若输出未触发换行或缓冲区未满,可能不会立即显示,需在输出后强制刷新:
fprintf(stdout, "text data: %s\n", buffer); fflush(stdout); // 强制刷新输出缓冲区
4. Mac系统网络接口配置
- 确保用
sudo执行程序,Mac抓包需要root权限 - 通过
ifconfig或ip link确认传入的设备名称正确(如en0、en1) - 可通过
ping或浏览网页触发数据包,确保接口有流量可捕获
5. pcap抓包参数优化
Mac下开启混杂模式需额外配置,若不需要可关闭以降低权限要求:
handle = pcap_open_live(device, BUFSIZ, 0, 1000, ERRBUF); // 关闭混杂模式
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/ethernet.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include <pcap.h> #define STARTING_INDEX 0 void packet_handler(u_char* args, const struct pcap_pkthdr* header, const u_char* rawdata); int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <device-name>\n", argv[0]); return 1; } char ERRBUF[PCAP_ERRBUF_SIZE]; memset(ERRBUF, 0, sizeof(ERRBUF)); pcap_if_t* devices; if (pcap_findalldevs(&devices, ERRBUF) == -1) { fprintf(stderr, "Failed to look up devices: %s\n", ERRBUF); return 1; } char device[BUFSIZ]; memset(device, 0, sizeof(device)); pcap_if_t* current_dev = devices; while (current_dev != NULL) { if (strcmp(argv[1], current_dev->name) == 0) { strncpy(device, current_dev->name, sizeof(device)-1); break; } current_dev = current_dev->next; } pcap_freealldevs(devices); if (strlen(device) == 0) { fprintf(stderr, "Specified device %s not found.\n", argv[1]); return 1; } struct bpf_program fp; char filter_exp[] = ""; bpf_u_int32 net; bpf_u_int32 mask; if (pcap_lookupnet(device, &net, &mask, ERRBUF) == -1) { fprintf(stderr, "Failed to get netmask of device: %s\n", ERRBUF); net = 0; } pcap_t* handle; handle = pcap_open_live(device, BUFSIZ, 0, 1000, ERRBUF); if (handle == NULL) { fprintf(stderr, "Failed to start sniffing session on device %s: %s\n", device, ERRBUF); return 1; } int datalink_type = pcap_datalink(handle); printf("Datalink type: %i\n", datalink_type); fflush(stdout); if (pcap_compile(handle, &fp, filter_exp, 1, net) == -1) { fprintf(stderr, "Failed to compile filter: %s\n", pcap_geterr(handle)); pcap_close(handle); return 1; } if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Failed to set filter: %s\n", pcap_geterr(handle)); pcap_close(handle); return 1; } printf("Starting packet capture...\n"); fflush(stdout); if (pcap_loop(handle, 0, packet_handler, NULL) == -1) { fprintf(stderr, "Failed to start capture loop: %s\n", pcap_geterr(handle)); pcap_close(handle); return 1; } pcap_close(handle); return 0; } void packet_handler(u_char* args, const struct pcap_pkthdr* header, const u_char* rawdata) { fprintf(stdout, "\n=== Packet Captured ===\n"); fprintf(stdout, "Timestamp: %s", ctime(&header->ts.tv_sec)); // ctime自带换行 fprintf(stdout, "Capture length: %d\n", header->caplen); fprintf(stdout, "Original length: %d\n", header->len); if (header->caplen == 0) { fflush(stdout); return; } char* buffer = malloc(sizeof(u_char) * (header->caplen + 1)); // 多分配1字节存终止符 if (buffer == NULL) { fprintf(stderr, "Failed to allocate memory.\n"); fflush(stderr); return; } memset(buffer, 0, sizeof(u_char) * (header->caplen + 1)); int buffer_len = STARTING_INDEX; for (int i = STARTING_INDEX; i < header->caplen; i++) { if (buffer_len < header->caplen && isprint(rawdata[i])) { buffer[buffer_len] = (char)rawdata[i]; buffer_len++; } } fprintf(stdout, "Printable text: %s\n", buffer); fflush(stdout); free(buffer); }
编译与运行
- 编译代码:
gcc -o sniffer sniffer.c -lpcap - 查看可用设备:
ifconfig - 运行程序:
sudo ./sniffer en0(替换en0为你的网络接口)
内容的提问来源于stack exchange,提问作者C Enjoyer
相关产品推荐
相关产品推荐

