使用 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 權限開啟混雜模式
pcap_compile + pcap_setfilter,如 "tcp port 80" 降低內核拷貝開銷。pcap_next_ex 非阻塞輪詢模式適配事件循環。pcap_dump_open / pcap_dump。ntohs/ntohl 配合結構體屬性 __attribute__((packed)) 確保對齊。