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

ARP欺骗场景下Linux C语言嗅探器开发相关技术咨询

Answers to Your Sniffer Development Questions

Great question—let’s break this down step by step, since you’re already deep into ARP spoofing and building a sniffer, which is a solid hands-on way to learn network internals.

1. Capturing Packets with Layer 2 Destination MAC but Non-Matching Layer 3 IP

You’re exactly right: link-layer RAW sockets are what you need here. Let me explain why:

When your NIC receives a frame with its MAC as the destination but a non-local IP, the kernel’s IP stack will discard it before it reaches any user-space sockets that operate at the IP layer (like SOCK_RAW with PF_INET). To bypass this, you need to capture frames directly at the Ethernet layer, before the kernel processes them further.

The correct socket type for this is PF_PACKET (or AF_PACKET—they’re equivalent on most systems) with SOCK_RAW, combined with the ETH_P_ALL protocol to capture all Ethernet frame types.

Here’s a minimal example to get you started:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <net/ethernet.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <arpa/inet.h>

int main() {
    int sockfd;
    struct sockaddr_ll sll;
    struct ifreq ifr;
    char buffer[ETH_FRAME_LEN]; // Max Ethernet frame size
    ssize_t bytes_read;

    // Create link-layer RAW socket
    sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd == -1) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // Bind to your specific NIC (replace "eth0" with your interface name)
    strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
    if (ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1) {
        perror("ioctl SIOCGIFINDEX failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    memset(&sll, 0, sizeof(sll));
    sll.sll_family = AF_PACKET;
    sll.sll_ifindex = ifr.ifr_ifindex;
    sll.sll_protocol = htons(ETH_P_ALL);

    if (bind(sockfd, (struct sockaddr*)&sll, sizeof(sll)) == -1) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // Start capturing packets
    printf("Capturing packets on eth0...\n");
    while (1) {
        bytes_read = recvfrom(sockfd, buffer, ETH_FRAME_LEN, 0, NULL, NULL);
        if (bytes_read == -1) {
            perror("recvfrom failed");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        // Parse Ethernet header (optional, for demonstration)
        struct ether_header *eth_hdr = (struct ether_header*)buffer;
        printf("Received frame: Source MAC: ");
        for (int i = 0; i < 6; i++) {
            printf("%02x%s", eth_hdr->ether_shost[i], (i < 5) ? ":" : "");
        }
        printf(", Destination MAC: ");
        for (int i = 0; i < 6; i++) {
            printf("%02x%s", eth_hdr->ether_dhost[i], (i < 5) ? ":" : "");
        }
        printf(", Frame type: 0x%04x\n", ntohs(eth_hdr->ether_type));
    }

    close(sockfd);
    return 0;
}

Key notes about this code:

  • You need to run it with root privileges (use sudo), since RAW sockets require elevated permissions.
  • Replace "eth0" with your actual network interface name (you can find this with ip link show).
  • ETH_P_ALL tells the socket to capture all Ethernet frame types (ARP, IP, IPv6, etc.). If you only want IP packets, you could use ETH_P_IP instead.

2. Setting NIC to Promiscuous Mode in C

Yes, you absolutely can set your NIC to promiscuous mode using C. This mode tells the NIC to accept all frames on the network segment, not just those addressed to its MAC (or broadcast/multicast). While ARP spoofing already redirects traffic to your MAC, promiscuous mode is still useful if you want to capture other traffic on the network (though it’s not strictly required for the specific packets you mentioned).

Here’s how to modify the previous code to enable promiscuous mode:

Add this section right after creating the socket (before binding):

// Enable promiscuous mode on the NIC
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == -1) {
    perror("ioctl SIOCGIFFLAGS failed");
    close(sockfd);
    exit(EXIT_FAILURE);
}

ifr.ifr_flags |= IFF_PROMISC;

if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) == -1) {
    perror("ioctl SIOCSIFFLAGS failed");
    close(sockfd);
    exit(EXIT_FAILURE);
}

printf("Promiscuous mode enabled on eth0\n");

To disable promiscuous mode later (cleanup), you would clear the IFF_PROMISC flag:

ifr.ifr_flags &= ~IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifr);

Important Notes:

  • Again, root privileges are required to modify NIC flags.
  • Promiscuous mode may be restricted by some network switches (if they use port security or are managed switches), but it works fine on unmanaged switches and most home networks.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:24:24