ARP欺骗场景下Linux C语言嗅探器开发相关技术咨询
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 withip link show). ETH_P_ALLtells the socket to capture all Ethernet frame types (ARP, IP, IPv6, etc.). If you only want IP packets, you could useETH_P_IPinstead.
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

