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

np8igboo  于 2023-03-12  发布在  Mac
关注(0)|答案(1)|浏览(198)

此问题在此处已有答案

'SOCK_RAW' option in 'socket' system call(1个答案)
2天前关闭。
我尝试在Linux系统中通过C函数sendto()发送一个以太网帧。该帧不包含任何IP级别信息,因为IP协议在我的应用程序中没有使用。
sendto() documentation提供以下信息:

函数sendto()的签名

ssize_t sendto(整数套接字fd、常量空值 * 缓冲区、大小_t长度、整数标志、常量结构套接字地址 * 目的地址、套接字长度_t地址长度);

要传输的缓冲区

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

目标地址

如果sendto()用于连接模式(SOCK_STREAM,SOCK_SEQPACKET)套接字,则忽略参数dest_addr和addrlen(当它们不为NULL和0时,可能会返回错误EISCONN),并且当套接字未实际连接时,会返回错误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地址自动设置为发送所用Ethernet接口的MAC地址。
我的问题
是否可以发送一个源MAC地址与用于发送的Ethernet接口的MAC地址不同的帧Ethernet?

**EDIT:**问题的解决方法是修改创建套接字的指令,用SOCK_RAW替换SOCK_DGRAM,正确的指令为:

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 (set to 0x0200 and this is the data lenght)

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

Wikipedia link说明了以太网帧结构。

lnlaulya

lnlaulya1#

最简单的解决方案是改变以太网卡上的mac地址。
如果你愿意,你可以使用tc & iptables solution. iptables来设置包类,例如基于udp端口,然后你可以使用tc来更改包类的源mac地址。

相关问题