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

Linux开发数据包嗅探器:如何通过结构体与原始套接字获取MAC地址?

Hey there! Let's walk through how to correctly extract and print source/destination MAC addresses in your Linux packet sniffer—your initial approach using struct ether_header is totally on the right track, so let's flesh it out properly.

The Core Idea: Using struct ether_header

The <net/ethernet.h> header defines struct ether_header, which maps exactly to the 14-byte Ethernet frame header. It has three key fields:

  • ether_dhost[6]: 6-byte destination MAC address
  • ether_shost[6]: 6-byte source MAC address
  • ether_type: 2-byte field indicating the upper-layer protocol (e.g., IP, ARP)

Full Working Code Example

Here's a complete, error-handled version of your sniffer that properly prints MAC addresses in standard format:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <arpa/inet.h>

int main() {
    int sock_fd;
    unsigned char packet_buf[1024];
    struct sockaddr_ll sock_addr;
    socklen_t addr_len = sizeof(sock_addr);

    // Create raw socket to capture all Ethernet frames
    sock_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sock_fd == -1) {
        perror("Failed to create raw socket");
        exit(EXIT_FAILURE);
    }

    printf("Sniffing packets (press Ctrl+C to stop)...\n\n");

    // Continuously capture and process packets
    while (1) {
        ssize_t bytes_read = recvfrom(
            sock_fd,
            packet_buf,
            sizeof(packet_buf),
            0,
            (struct sockaddr *)&sock_addr,
            &addr_len
        );

        if (bytes_read == -1) {
            perror("Failed to receive packet");
            close(sock_fd);
            exit(EXIT_FAILURE);
        }

        // Cast buffer to Ethernet header structure
        struct ether_header *eth_header = (struct ether_header *)packet_buf;

        // Print Destination MAC (use %02x to ensure 2-digit hex with leading zeros)
        printf("Destination MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
               eth_header->ether_dhost[0], eth_header->ether_dhost[1],
               eth_header->ether_dhost[2], eth_header->ether_dhost[3],
               eth_header->ether_dhost[4], eth_header->ether_dhost[5]);

        // Print Source MAC
        printf("Source MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
               eth_header->ether_shost[0], eth_header->ether_shost[1],
               eth_header->ether_shost[2], eth_header->ether_shost[3],
               eth_header->ether_shost[4], eth_header->ether_shost[5]);

        // Optional: Print upper-layer protocol type (convert from network to host byte order)
        printf("EtherType: 0x%04x\n\n", ntohs(eth_header->ether_type));
    }

    close(sock_fd);
    return 0;
}

Key Details to Note

  • %02x vs %x: Using %02x ensures each byte is printed as two hexadecimal digits (e.g., 0a instead of a), which matches the standard MAC address format (AA:BB:CC:DD:EE:FF).
  • Raw Socket Permissions: You must run this program as root (use sudo ./your_sniffer), since creating raw sockets requires the CAP_NET_RAW privilege.
  • EtherType Conversion: The ether_type field is stored in network byte order (big-endian), so we use ntohs() to convert it to host byte order before printing.
  • Filtering Packets: If you don't want to capture all frames, replace ETH_P_ALL with a specific protocol type (e.g., htons(ETH_P_IP) for IP packets only).

Compilation & Execution

Compile with gcc:

gcc sniffer.c -o sniffer

Run with root privileges:

sudo ./sniffer

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:52:49