2

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

在客户端软件中,我以相同的方式创建套接字,然后从该套接字执行一个 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

4

1 回答 1

2

你可能应该使用

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

而不是 SOCK_RAW 套接字。使用 SOCK_RAW,您可以发送/接收整个以太网帧,包括源 MAC 地址和目标 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);
于 2013-11-06T23:05:23.290 回答