首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

libpcap 抓包實戰:提取 Ethernet/IP/TCP 關鍵信息完整代碼

     編輯:關於C語言

程序功能

使用 libpcap 捕獲數據包,解析以太網幀、IPv4 頭、TCP 頭,輸出源/目的 MAC、IP、端口。僅處理 Ethernet + IPv4 + TCP 協議棧。

關鍵結構體定義(對應協議頭)

// 以太網頭 (14 bytes)
typedef struct ether {
    u_char dest[6];   // 目的 MAC
    u_char src[6];    // 源 MAC
    u_short proto;    // 上層協議 (0x0800 = IP)
    u_char data[0];   // 柔性數組,指向載荷
} tEther;

// IPv4 頭 (最小 20 bytes)
typedef struct ip {
    u_char hlen;      // 版本(4bit) + 首部長度(4bit)
    u_char tos;
    u_short len;      // 總長度
    u_short ipid;
    u_short flagoff;
    u_char ttl;
    u_char proto;     // 協議 (6 = TCP)
    u_short cksum;
    u_int src;        // 源 IP (網絡序)
    u_int dest;       // 目的 IP
    u_char data[0];
} tIp;

// TCP 頭 (最小 20 bytes)
typedef struct tcp {
    u_short sport;    // 源端口
    u_short dport;    // 目的端口
    u_int seq;
    u_int ack;
    u_char hlen;      // 數據偏移/保留
    u_char code;      // 標志位
    u_short window;
    u_short chsum;
    u_short urg;
    char data[0];
} tTcp;

回調處理函數

void proc_pkt(u_char *user, const struct pcap_pkthdr *hp, const u_char *packet) {
    tEther *eth = (tEther *)packet;
    if (ntohs(eth->proto) != 0x0800) return;  // 非 IPv4

    tIp *ip = (tIp *)eth->data;
    if (ip->proto != 6) return;               // 非 TCP

    tTcp *tcp = (tTcp *)ip->data;

    // 輸出 MAC (注意網絡序轉主機序)
    printf("目的 MAC: ");
    for (int i = 0; i < 6; i++) printf("%02x%c", eth->dest[i], i==5?'\n':':');
    printf("源 MAC: ");
    for (int i = 0; i < 6; i++) printf("%02x%c", eth->src[i], i==5?'\n':':');

    // 輸出 IP (ntohl 或逐字節)
    auto print_ip = [](u_int addr) {
        u_char *b = (u_char*)&addr;
        printf("%u.%u.%u.%u\n", b[0], b[1], b[2], b[3]);  // 小端機器上需調整順序
    };
    printf("源 IP: "); print_ip(ip->src);
    printf("目的 IP: "); print_ip(ip->dest);

    // 輸出端口
    printf("源端口: %hu\n", ntohs(tcp->sport));
    printf("目的端口: %hu\n\n", ntohs(tcp->dport));
}

主程序流程

int main() {
    char errbuf[PCAP_ERRBUF_SIZE];
    char *dev = pcap_lookupdev(errbuf);  // 自動選設備
    if (!dev) { fprintf(stderr, "%s\n", errbuf); return 1; }

    pcap_t *handle = pcap_open_live(dev, BUFSIZ, 0, 100, errbuf);
    if (!handle) { fprintf(stderr, "%s\n", errbuf); return 1; }

    printf("監聽設備: %s\n", dev);
    pcap_loop(handle, -1, proc_pkt, NULL);  // -1 = 無限循環
    pcap_close(handle);
    return 0;
}

編譯與運行

gcc -o pcap_demo pcap_demo.c -lpcap
sudo ./pcap_demo   # 需 root 權限開啟混雜模式

進階擴展建議

  • 添加 BPF 過濾器:pcap_compile + pcap_setfilter,如 "tcp port 80" 降低內核拷貝開銷。
  • 處理 IP 分片、TCP 選項、VLAN 標籤等實際網絡複雜情況。
  • 使用 pcap_next_ex 非阻塞輪詢模式適配事件循環。
  • 保存 pcap 文件:pcap_dump_open / pcap_dump。

常見問題排查

  1. 權限不足:需 root 或 CAP_NET_RAW 權限。
  2. 看不到包:確認接口 up、有流量、防火牆未攔截、非回環口捕獲外部流量。
  3. IP/MAC 順序顛倒:注意大小端轉換,ntohs/ntohl 配合結構體屬性 __attribute__((packed)) 確保對齊。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved