Linux下使用sendto()发送自定义源MAC地址的以太网帧
能否发送源MAC与网卡MAC不同的以太网帧?
可以。当你使用socket(AF_PACKET, SOCK_DGRAM, 0)创建套接字时,系统会自动填充以太网帧的源MAC地址为发送网卡的物理地址,无法自定义。但通过使用原始套接字(SOCK_RAW),你可以完全手动构造以太网帧的头部,包括自定义源MAC地址。
实现步骤
- 创建
AF_PACKET类型的原始套接字:socket(AF_PACKET, SOCK_RAW, 0) - 在发送缓冲区的前14字节手动构造以太网帧头:
- 前6字节:目的MAC地址
- 接下来6字节:自定义的源MAC地址
- 最后2字节:以太网类型(例如
0x0200对应IEEE 802.3原始帧)
- 调用
sendto()发送构造好的完整帧
示例代码
#include <sys/socket.h> #include <netpacket/packet.h> #include <net/ethernet.h> #include <string.h> #include <stdio.h> #include <unistd.h> #define BUFFSIZE 1024 // 根据实际需求调整缓冲区大小 int main() { int sck_raw = socket(AF_PACKET, SOCK_RAW, 0); if (sck_raw == -1) { perror("socket creation failed"); return 1; } char buf[BUFFSIZE + 14]; struct sockaddr_ll dest_addr = {0}; // 配置目的地址结构体:指定发送网卡接口 dest_addr.sll_family = AF_PACKET; dest_addr.sll_ifindex = 2; // 替换为你的网卡接口索引,可通过`ip link`查看 dest_addr.sll_halen = ETH_ALEN; // 手动构造以太网帧头 // buf[0]~buf[5]: 目的MAC地址(示例:00:11:22:33:44:55) buf[0] = 0x00; buf[1] = 0x11; buf[2] = 0x22; buf[3] = 0x33; buf[4] = 0x44; buf[5] = 0x55; // buf[6]~buf[11]: 自定义源MAC地址(示例:AA:BB:CC:DD:EE:FF) buf[6] = 0xAA; buf[7] = 0xBB; buf[8] = 0xCC; buf[9] = 0xDD; buf[10] = 0xEE; buf[11] = 0xFF; // buf[12]~buf[13]: 以太网类型(0x0200表示IEEE 802.3原始帧,网络字节序) buf[12] = 0x00; buf[13] = 0x02; // 填充帧数据部分(buf+14开始,示例填充测试数据) memset(buf+14, 0x01, BUFFSIZE); // 发送帧 ssize_t sent_bytes = sendto(sck_raw, buf, BUFFSIZE + 14, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); if (sent_bytes == -1) { perror("sendto failed"); close(sck_raw); return 1; } printf("Sent %zd bytes\n", sent_bytes); close(sck_raw); return 0; }
注意事项
- 使用原始套接字需要root权限运行程序
- 网卡接口索引可通过
ip link命令查看(例如eth0的索引可能为2) - 以太网类型字段需使用网络字节序(大端序)
- 构造的帧需符合以太网帧格式规范,否则可能无法被目标设备正确解析
内容的提问来源于stack exchange,提问作者User051209
相关产品推荐
相关产品推荐

