发送带有任意源MAC地址的以太网帧[重复]

问题描述 投票:0回答:1

我正在尝试通过 C 函数

sendto()
在 Linux 系统中发送帧以太网。该帧不包含任何 IP 级别信息,因为 IP 协议未在我的应用程序中使用。
sendto() 文档 提供了以下信息:

函数 sendto() 的签名

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

传输缓冲区

对于 send() 和 sendto(),消息在 buf 中找到,长度为 len。

目的地地址

如果在连接模式(SOCK_STREAM、SOCK_SEQPACKET)套接字上使用 sendto(),参数 dest_addr 和 addrlen 将被忽略(当它们不为 NULL 和 0 时可能会返回错误 EISCONN),当它们不为 NULL 和 0 时返回错误 ENOTCONN插座实际上没有连接。 否则,目标的地址由 dest_addr 给出,addrlen 指定其大小。

在我的例子中,套接字是通过以下指令创建的:

int sck_dgram = socket(AF_PACKET, SOCK_DGRAM, 0);

所以它不是连接模式套接字。要设置目标地址,我使用以下说明:

struct sockaddr_ll dest_addr = {0};
dest_addr.sll_family = AF_PACKET;
dest_addr.sll_ifindex = ifindex;
dest_addr.sll_halen = ETHER_ADDR_LEN;
memcpy(dest_addr.sll_addr, mac_dest, ETHER_ADDR_LEN);

其中

mac_dest
是包含目标 MAC 地址的数组,
ifindex
是用于发送的以太网接口的索引。

我的 sendto() 指令

总之,要发送

buf[BUFFSIZE]
数据数组,我使用以下
sendto()
指令:

sendto(sck_dgram, buf, BUFFSIZE, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr))

使用前面的指令,我只能通过

dest_addr
设置目标MAC地址(帧的0到5字节)而不是帧的源MAC地址(帧的6到11字节)。源 MAC 地址自动设置为等于用于发送的以太网接口的 MAC 地址。

我的问题

是否可以发送源 MAC 地址与用于发送的以太网接口的 MAC 地址不同的帧以太网?


编辑: 问题的解决方案是通过将

SOCK_DGRAM
替换为
SOCK_RAW
来修改创建套接字的指令。正确的指示是:

int sck_raw = socket(AF_PACKET, SOCK_RAW, 0);

根据之前的指令,我必须修改

sendto()
指令,使
buf[]
包含14个八位字节,包括目标mac地址、源mac地址和以太网类型。此数据必须放在
buf[]
的前 14 个字节中。所以我必须增加
buf
的大小如下:

char buf[BUFFSIZE+14];

// set buf[0] .. buf[5] with mac dest
// set buf[6] .. buf[11] with mac source
// set buf[12] and buf[13] with ether type (in my case set 0x0200)

// sendto() becomes:
sendto(sck_raw, buf, BUFFSIZE+14, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr))

在这个link可以知道以太网帧结构。

c linux send mac-address raw-ethernet
1个回答
0
投票

最简单的解决方案是更改以太网卡上的 mac 地址。

如果你愿意,你可以使用 tc & iptables 解决方案。 iptables 根据 udp 端口设置数据包类别,然后您可以使用 tc 更改数据包类别的源 mac 地址。

© www.soinside.com 2019 - 2024. All rights reserved.