You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

编译与运行

  1. 编译代码:gcc -o sniffer sniffer.c -lpcap
  2. 查看可用设备:ifconfig
  3. 运行程序:sudo ./sniffer en0(替换en0为你的网络接口)

内容的提问来源于stack exchange,提问作者C Enjoyer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:07:04