【问题标题】:Incorrect MAC printed in C code在 C 代码中打印的 MAC 不正确
【发布时间】:2013-05-25 19:30:53
【问题描述】:

我有这段代码,它应该从我正在侦听的套接字打印每个数据包的目标 MAC 地址和源 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 也不是我所期望的。

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

谢谢!

【问题讨论】:

    标签: c sockets ethernet mac-address


    【解决方案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;
    }
    

    【讨论】:

    • 太棒了!!非常感谢您的帮助,现在可以正常使用了。您能否提供一个指向您从中阅读此内容的页面的链接?
    • @user2129635 它来自man 7 raw,也就是说,您必须在安装了相关手册页包的 linux 系统上输入。
    猜你喜欢
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 2019-11-29
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    相关资源
    最近更新 更多