原始以太网套接字填充sockaddr_ll

时间:2013-11-06 15:29:15

标签: c sockets raw-ethernet

我在调用socket()时使用PF_PACKET和SOCK_RAW以及自定义协议来构建服务器/客户端软件

在客户端软件中,我以相同的方式创建套接字,只需从该套接字执行rcv即可获取数据

我的问题是我是否必须以与服务器相同的方式填写sockaddr_ll结构,因为当我从客户端回复时,我得到的源MAC地址是一个奇怪的类似于 11:11:00:00:00:00当然这不是我客户的MAC

有谁知道这会发生什么? 打开插座

if ( (sckfd=socket(PF_PACKET, SOCK_RAW, htons(proto)))<0)
{
    myError("socket");

}

这是我收到数据的方式

n = recvfrom(sckfd, buffer, 2048, 0, NULL, NULL);
printf("%d bytes read\n",n);

所以这就是我在没有填充struct sockaddr_ll的情况下基本上在客户端接收数据的方法

对于服务器程序,我必须填写结构

struct sockaddr_ll saddrll;
memset((void*)&saddrll, 0, sizeof(saddrll));
saddrll.sll_family = PF_PACKET;   
saddrll.sll_ifindex = ifindex;
saddrll.sll_halen = ETH_ALEN;
memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);

我的问题是我收到如图所示并按照所示发送,当我回复服务器时,调用服务器中使用的相同功能进行发送,然后在接收客户端时我得到的是11:11:00:00:00:00回复

1 个答案:

答案 0 :(得分:1)

您应该使用

socket(AF_PACKET, SOCK_DGRAM, htons(proto)))

而不是SOCK_RAW套接字。使用SOCK_RAW,您将发送/接收整个以太网帧,包括源和目标MAC地址。使用SOCK_DGRAM,内核将填写以太网头。

您可能希望将回复发送到请求来自的相同地址,recvfrom()可以填写源地址;

struct sockaddr_ll src_addr;
socklen_t addr_len = sizeof src_addr;
n = recvfrom(sckfd, buffer, 2048, 0, 
            (struct sockaddr*)&src_addr, &addr_len);

现在您已经学习了源地址,因此请将数据包发回给它:

...
sendto(sckfd, data, data_len, src_addr, addr_len);

如果您需要使用SOCK_RAW,您也将收到以太网标头,因此只需从接收到的数据中复制出MAC地址,并在构建应答帧时将其交换。

对于SOCK_RAW套接字,您可以创建整个以太网帧,不需要填写以太网地址,因此不需要以下内容;

 memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);