0

我有这段代码,它应该从我正在监听的套接字打印每个数据包的目标和源 MAC 地址:

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(sock_raw < 0)
{
    printf("Socket Error\n");
    return 1;
}
while(1)
{
    saddr_size = sizeof saddr;
    //Receive a packet
    data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size);
    if(data_size <0 )
    {
        printf("Recvfrom error , failed to get packets\n");
        return 1;
    }
    //Now process the packet
    ProcessPacket(buffer , data_size);
}
close(sock_raw);

............

fprintf(logfile,"\n###########################################################");

struct ether_header *ethh;
ethh = (struct ether_header *)Buffer;

fprintf(logfile,"\n\n***********************ETHERNET Packet*************************\n");

fprintf(logfile,"\n");
fprintf(logfile,"Ethernet Header\n");
fprintf(logfile,"   |-Source Address      : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_dhost));
fprintf(logfile,"   |-Destination Address : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_shost));
fprintf(logfile,"\n");
fprintf(logfile,"\n###########################################################");

问题是当我运行 ping 或其他操作时,我希望在我的 ether_addr 结构的 ether_dhost 变量中看到我正在监听的 PC 的 MAC。但是,从该变量打印的 MAC 不是我的。此外,源 MAC 也不是我所期望的。

有人可以向我解释发生了什么并可能为我的代码提供修复吗?

谢谢!

4

1 回答 1

1

在 sock_raw 手册页中,“原始套接字允许在用户空间中实现新的 IPv4 协议。原始套接字接收或发送不包括链接级别标头的原始数据报。”。因此,在您的示例中,即使您将缓冲区转换为以太网标头结构,您实际上并没有获得以太网标头。

要接收以太网标头,您需要一个 AF_PACKET 套接字。这是您的代码的调整版本,应该可以满足您的需求。

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>

static FILE *logfile;

static void ProcessPacket(const void *Buffer, ssize_t data_size) {

    fprintf(logfile,"\n###########################################################");

    struct ether_header *ethh;
    ethh = (struct ether_header *)Buffer;

    fprintf(logfile,"\n\n***********************ETHERNET Packet*************************\n");

    fprintf(logfile,"\n");
    fprintf(logfile,"Ethernet Header\n");
    fprintf(logfile,"   |-Source Address      : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_dhost));;
    fprintf(logfile,"   |-Destination Address : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_shost));
    fprintf(logfile,"\n");
    fprintf(logfile,"\n###########################################################");
}

int main(int argc, char **argv) {
    logfile = stdout;

    int sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    char buffer[65536];
    if(sock_raw < 0)
    {
        printf("Socket Error\n");
        return 1;
    }
    while(1)
    {
        //Receive a packet
        ssize_t data_size = recvfrom(sock_raw , buffer , sizeof(buffer) , 0 , NULL, NULL);
        if(data_size <0 )
        {
            printf("Recvfrom error , failed to get packets\n");
            break;
        }
        //Now process the packet
        ProcessPacket(buffer , data_size);
    }
    close(sock_raw);
    return 0;
}
于 2013-05-25T20:35:46.397 回答